<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Terry.Li-彬

    虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks
    使用定制的 Web Service Appender for Log4j 將日志信息發送到某一集中位置。Log4j Appender 使您可以在面向服務架構 (SOA) 解決方案中調試和跟蹤任意問題。

    引言

    你 可以使用 Web Service Appender 將日志集中到某一位置,同時,Web Service Appender 允許管理者監控、開發者調試面向服務架構(SOA)環境里可能存在的任何問題。Web Service Appender 是一種擴展 JAVA 類,它由 Log4j 的 Appender 類擴展而來。

    從定義上看,SOA 是一種彼此可以互相通信的服務集合,但這些服務的內容是各自獨立的,每一類服務均不受其它服務內容或服務狀態的影響,并且這些服務都工作在分布式的系統架 構里。在 SOA 中,Web 服務通常被用來在給定事務中處理請求,這些請求可以是遺留代碼、企業級 Java Beans(EJBs) 的封裝,也可以是 Java 類的封裝,使用一種可以將日志信息聚集在中心位置里的日志紀錄方法,能幫助您隔離缺陷和問題,并能讓你更好的理解邏輯流的處理。

    將特定模塊或服務的日志消息紀錄到一個中心位置的機制,可以把可能潛在的問題和缺陷降低到最小。

    本文對 Log4j 的功能進行了大體的概述,并介紹了如何編寫自定義的 Log4j Appender,這類特殊的 Appender 將日志消息編到一種特定的 Web 服務。





    回頁首


    Log4j 快速入門

    Log4j 是一種開放源代碼的日志庫,它已被發展為 Apache Software Foundation 日志服務項目的子項目。該庫是以 IBM 在 90 年代末開發的日志庫為基礎的,第一版發布于 1999 年。現在它在開放源代碼團體得到了廣泛使用,它的體系是圍繞以下三個主要概念構建起來的:

    • Logger
    • Appender
    • Layout

    這些概念可以讓您根據消息類型、消息優先級來紀錄消息,您可以控制消息在何處結束及消息如何格式化。 Logger 是應用程序首先調用以初始化消息紀錄的對象。當把某一消息傳遞給日志時,logger 會生成 LoggingEvent,對消息進行封裝。之后,Logger 對象將 LoggingEvent 傳遞給與之關聯的 Appender。

    Appender 將 LoggingEvent 所包含的消息發送給指定的目標輸出文件。所謂指定的文件,大多數情況下,是 Log4 屬性文件。一些 Appender 存在于 Log4j 中。您也可以擴展 Appender,使之支持其它的目標文件,比如 XML 文件、控制臺等等。

    在 Log4j 里, LoggingEvent 被賦予某一級別,以表明它們的優先級。缺省的級別包括如下幾種:

    • OFF:可能是最高的級別,它是用來關閉日志紀錄的
    • FATAL:指出現了非常嚴重的錯誤事件,這些錯誤可能會導致應用程序異常中止
    • ERROR:指雖有錯誤,但仍允許應用程序繼續運行
    • WARN:指運行環境潛藏著危害
    • INFO:指報告信息,這些信息在粗粒度級別上突出顯示應用程序的進程
    • DEBUG:指細粒度信息事件,細粒度信息事件對于應用程序的調試是最有用的
    • ALL:可能是最低的級別,其目的是打開所有日志記錄
    Logger 和 Appender 也被賦予上述的某一級別,并且僅執行等于或高于它們自身的級別的日志請求。比如,如果一個 Appender 屬于 INFO 級別,而日志請求屬于 DEBUG,那么 Appender 將不會為給定的日志事件寫消息。



    回頁首


    客戶端組件

    客戶端 log4j.properties 文件

    客戶端 log4j.properties 文件是一種標準文件,它包含服務或模塊使用的所有 Appender。Web Service Appender 要求有一個端點(endpoint) 屬性以指定所使用的日志服務。

    清單 1 描述了使用 WebServiceAppender 所必需的 Web 服務客戶端 Log4j 屬性。 黑體顯示的文本指明了將訪問 WebServiceAppender 服務器端的 Appender。屬性文件是使用 Log4j 的基本需求,它可以讓您配置應用程序以使用多個 Appender 以及 logging severity。一旦應用程序進入運行狀態或潛在的問題得到解決,您就可以輕松地修改屬性文件。


    清單 1:客戶端 Log4j 的屬性文件

    #set the level of the root logger
    log4j.rootLogger = INFO, CONSOLE
    #set own logger
    log4j.logger.com.carmelouria.logging.test=CONSOLE
    log4j.appender.CONSOLE=com.carmelouria.logging.WebServiceAppender
    log4j.appender.CONSOLE.endpoint=
    http://localhost:9080/log4j/services/LogAppenderService

    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n





    回頁首


    服務器的 Log4j.properties 文件

    服 務器 Log4j.properties 文件被用來關聯客戶端 Log4j 屬性文件,它指定了日志的級別及服務器將如何輸出消息。對于支持 Log4j 的應用程序,您可以定義多個 appender。當然,這些 appender 既可以用于客戶端服務,也可以用于服務模塊。

    清單 2 描述了一份典型的 Log4j 屬性文件,服務器端的 WebServiceAppender 使用缺省的 Log4j Appenders。服務器端的 Appender 可以潛在的調用另一個 WebServiceAppender,并將日志信息鏈接起來:


    清單 2:服務器端的 Log4j 屬性文件

    #set the level of the root logger
    log4j.rootLogger = INFO, FILE
    #set own logger
    log4j.appender.FILE=org.apache.log4j.RollingFileAppender
    log4j.appender.FILE.file=c:/temp/log4j/server/server.log
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.FILE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n

    客戶端程序測試示例:

    這個客戶端程序示例是無格式普通 Java 對象(POJO),它記錄了一條消息,并被配置為使用 Web Service Appender 來處理消息。清單 3 顯示了這個示例:


    清單 3:客戶端應用程序使用 WebServiceAppender 的示例

    package com.carmelouria.logging.test;
    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.apache.log4j.PropertyConfigurator;
    /**
    * @author Carmelo Uria
    *
    */
    public class LoggingSample
    {
    private static Logger logger = Logger.getLogger(LoggingSample.class.getName());
    /**
    *
    */
    public LoggingSample()
    {
    super();
    PropertyConfigurator.configure("c:/temp/log4j.properties");
    logger.log(Level.INFO, "LoggingSample instantiation...");
    System.out.println("finished...");
    }
    public static void main(String[] args)
    {
    LoggingSample sample = new LoggingSample();
    }
    }





    回頁首


    WebServiceAppender

    WebServiceAppender 是必需的,它可以將消息發送到指定的 Web 服務。WebServiceAppender 繼承了 org.log4j.Appender,它允許使用 log4.properties,并成為有效的 Log4j Appender。

    WebServiceAppender 使用基于 XML 的遠程過程調用 (JAX-RPC) 的 Java API,來將消息發送到服務器。JAX-RPC 是一種規范,它描述使用 RPC 和 XML 構建 Web 服務和 Web 服務客戶端的應用編程接口 (API) 和約定。JAX-RPC 又被稱為 JSR 101。

    LoggingEvent 通過 SOAPElement 被分割并表示為 XML。javax.xml.soap.SOAPElement 接口意味著服務端點接口將包含一個參數,或返回 javax.xml.soap.SOAPElement 類型的值,以對應于 schema 中每個使用<xsd:any/>的地方。從本質上看,它是 XML 參數的封裝,且沒有相應的序列化/反序列化 JAVA 類。例如,一旦客戶請求記錄一個消息,就會創建一個 LoggEvent 對象,然后傳送給 Appender。在這種情況下,Appender 就是 WebServiceAppender。Appender 檢索事件,并在解析事件中的信息。一些額外的信息會被加入,如主機名稱,這樣您就知道這些消息來自哪個系統。同時,append 方法也將消息轉換為 SOAPElement,這樣就可以通過 executeWebService 方法將消息傳遞給 Web 服務。使用 SOAPElement 充分考慮了 WebServiceAppender 未來版本的可擴展性問題。


    清單4:執行 WebServiceAppender 服務的 Append 方法

    protected void append(LoggingEvent event)
    {
    // create Web Service client using endpoint
    if (endpoint == null)
    {
    System.out.println("no endpoint set. Check configuration file");
    System.out.println("[" + hostname + "] " + this.layout.format(event));
    return;
    }
    executeWebService(event);
    }
    private void executeWebService(LoggingEvent event)
    {
    SoapClient client = new SoapClient();
    URL endPoint = null;
    try
    {
    endPoint = new URL(getendpoint());
    }
    catch (MalformedURLException e1)
    {
    e1.printStackTrace();
    }
    String nameSpace = "http://ejb.logging.carmelouria.com";
    QName serviceName = new QName(nameSpace, "LogAppenderServiceService");
    QName operation = new QName(nameSpace, "log");
    QName port = new QName(nameSpace, "LogAppenderService");
    Parameter message =
    new Parameter("log", Constants.XSD_ANY, SOAPElement.class, ParameterMode.IN);
    try
    {
    /**
    *create SOAPElement from LoggingEvent need hostname
    */
    Level level = event.getLevel();
    String sysLog = "<syslog>" + new Integer(level.getSyslogEquivalent()).toString()
    + "</syslog>";
    String startTime = new Long(LoggingEvent.getStartTime()).toString();
    String timeTag = "<start_time>" + startTime + "</start_time>";
    String hostName = "<hostname>" + InetAddress.getLocalHost() +
    "</hostname>";
    String threadName = "<thread_name>" + event.getThreadName()
    +"</thread_name>";
    String logger = "<logger>" + event.getLoggerName() + "</logger>";
    String eventMessage = "<message>" + event.getRenderedMessage() +
    "</message>";
    String log = hostName + threadName + logger + timeTag + sysLog +
    eventMessage;
    String throwableInformation[] = event.getThrowableStrRep();
    if (throwableInformation != null)
    {
    for (int i = 0; i < throwableInformation.length; i++)
    {
    String throwable = "<throwable_information>" + throwableInformation[i] +
    "</throwable_information>";
    log += throwable;
    }
    }
    String ndcString = event.getNDC();
    if (throwableInformation != null)
    {
    String throwable = <ndc>" + ndcString + </ndc>";
    log += throwable;
    }
    message.setValue(SOAPElementFactory.create(<log>" + log + </log>"));
    }
    catch (UnknownHostException unknownHostException)
    {
    unknownHostException.printStackTrace();
    }
    catch (SOAPException e2)
    {
    e2.printStackTrace();
    }
    Parameter resultType = newParameter("logResponse",
    Constants.WEBSERVICES_VOID,
    Object.class,
    ParameterMode.OUT);
    Parameter[] parameters = { message };
    try
    {
    // execute client
    Object result =
    client.execute(endPoint, serviceName, operation, "wrapped", null,
    port, resultType, parameters);
    if ((result != null) && (result instanceof String))
    System.out.println((String) result);
    }
    catch (ClientException e)
    {
    e.printStackTrace();
    }
    }

    Hostname

    不幸的是,Log4j 的 LoggingEvent 沒有包含 Hostname,而 Hostname 是 Web Service Appender 眾多需求之一。在創建 SOAPElement 以前,您可以用下面的語句將 Hostname 添加到 XML 文件里:

    String hostName = "<hostname>" + InetAddress.getLocalHost() + "</hostname>";

    SoapElementFactory

    SoapElementFactory 是主要用于創建 SOAPElement 的類。它同時支持創建 IBM 和 Java 的 SOAPElement 實現,如清單 5 所示:


    清單 5:使用 SoapElementFactory 類的創建方法

    public static javax.xml.soap.SOAPElement create(String xml) throws SOAPException
    {
    com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory factory =
    (com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory)
    com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory
    .newInstance();
    SOAPElement element =
    (javax.xml.soap.SOAPElement)factory.createElementFromXMLString(xml);
    return(element);
    }
    public static SOAPElement create(String arg0, String arg1, String arg2,
    boolean ibmSoapElement) throws
    SOAPException
    {
    if (ibmSoapElement)
    {
    SOAPFactory soapFactory =
    (com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory)
    com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory.newInstance();
    return (soapFactory.createSOAPElement(arg0, arg1));
    }
    javax.xml.soap.SOAPFactory soapFactory =
    javax.xml.soap.SOAPFactory.newInstance();
    return (soapFactory.createElement(arg0, arg1, arg2));
    }

    SoapClient

    SoapClient 類封裝了 Call 接口的 JAX-RPC 實現,javax.xml.rpc.Call 接口提供了對服務端點動態調用的支持。javax.xml.rpc.Service 接口就好象是創建 Call 實例的工廠。

    清單 6 說明了客戶端如何動態調用服務。這允許對服務進行變更,而無需生成客戶端代理來訪問遠程服務。


    清單 6:使用 SoapClient 類的調用方法

    private Object call(SoapService service, QName operation, QName portType,
    String operationStyleProperty,
    String encodingURIProperty, Parameter returnType,
    Parameter[] parameters) throws ClientException
    {
    QName portName;
    String response = null;
    Object results = null;
    Call call = null;
    try
    {
    // check to see if Service object exists
    if (service == null)
    throw new ClientException("Invalid Service object. It maybe null.");
    // retrieve call from Service object
    call = service.createCall();
    call.setOperationName(operation);
    call.setPortTypeName(portType);
    // check call object
    if (call == null)
    throw new ClientException("invalid operation. Call object is null.");
    // set default values
    if (operationStyleProperty == null)
    call.setProperty(Call.OPERATION_STYLE_PROPERTY,
    OPERATION_STYLE_DOCUMENT_TYPE);
    else
    call.setProperty(Call.OPERATION_STYLE_PROPERTY,
    operationStyleProperty);
    if (encodingURIProperty == null)
    call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY,
    ENCODING_LITERAL);
    else
    call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY,
    encodingURIProperty);
    call.setTargetEndpointAddress(service.getServiceEndPoint());
    //create Parameter class for SoapClient
    for (int i = 0; i < parameters.length; i++)
    {
    Class classObject = parameters[i].getClassObject();
    if (classObject != null)
    call.addParameter(parameters[i].getName(), parameters[i].getXmlType(),
    parameters[i].getClassObject(), parameters[i].getMode());
    else
    call.addParameter(parameters[i].getName(), parameters[i].getXmlType(),
    parameters[i].getMode());
    }
    // pass parameter as ReturnType
    if (returnType != null)
    {
    if (returnType.getClassObject() != null)
    call.setReturnType(returnType.getXmlType(), returnType.getClassObject());
    else
    call.setReturnType(returnType.getXmlType());
    }
    Object[] request = new Object[parameters.length];
    // add parameter values
    for (int i = 0; i < request.length; i++)
    {
    request[i] = parameters[i].getValue();
    }
    results = call.invoke(request);
    }
    catch (SOAPFaultException e)
    {
    System.out.println(e.getFaultString());
    e.getStackTrace();
    throw new ClientException(e.getLocalizedMessage(), e);
    }
    catch (ServiceException serviceException)
    {
    serviceException.getStackTrace();
    throw new ClientException(serviceException.getLocalizedMessage(),
    serviceException);
    }
    catch (RemoteException exception)
    {
    exception.printStackTrace();
    throw new ClientException(exception.getLocalizedMessage(), exception);
    }
    return (results); }





    回頁首


    服務組件

    Log4j.server.properties

    Log4j.server.properties 文件包含了一個基本的 Log4j 配置文件,該文件可以讓您指定把哪些日志發送給 Web 服務系統。


    清單 7:Log4j.server.properties 文件

    #set the level of the root logger
    log4j.rootLogger = INFO, FILE
    #set own logger
    log4j.appender.FILE=org.apache.log4j.RollingFileAppender
    log4j.appender.FILE.file=c:/temp/log4j/server/server.log
    log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.FILE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n

    LogAppenderBean.java

    LogAppenderBean.java 是 Web Service Appender 服務所要使用的 EJB。該服務啟動 LogAppenderBean 以處理來自每個 Web Service Appender 客戶端的每一個請求。

    清單 8 顯示了來自 WebServiceAppender EJB 的 log 方法,該方法解析來自客戶端的消息,并將客戶端信息紀錄到服務的服務器端。


    清單 8:LogAppenderBean 的 log 方法

    public void log(SOAPElement message)
    {
    try
    {
    InputSource source = ((IBMSOAPElement)
    message).toInputSource(false);
    Document document = Parser.parse(source);
    String log = null;
    String hostname =
    document.selectSingleNode("http://hostname").getText();
    String threadName =
    document.selectSingleNode("http://thread_name").getText();
    String syslog =
    document.selectSingleNode("http://syslog").getText();
    String startTime = new Long(
    document.selectSingleNode("http://start_time").
    getText()).toString();
    log = '[' + startTime + ':' + hostname + ':' + threadName +
    "] " + document.selectSingleNode(
    "http://message").getText();
    // retrieve any throwable messages
    List throwableList = document.selectNodes(
    "http://throwable_information");
    if(throwableList != null)
    {
    Iterator throwables = throwableList.iterator();
    while(throwables.hasNext())
    {
    log += '\n' + ((Node)throwables.next()).getText();
    }

    log += '\n';
    }

    logger.log(Level.toLevel(new Integer(syslog).intValue()),
    log);
    logger.log(Level.INFO,log);
    }
    catch(ParserException parseException)
    {
    parseException.printStackTrace();
    }
    catch (SAXException e)
    {
    e.printStackTrace();
    }
    }

    通過 IBM SOAPElement 的 InputSource,每一個 SOAPElement 的內容都會被檢索。目前,只有 IBM WebSphere? Application Server (Application Server) 支持這些代碼(請參閱參考資料)。 然而,如果您移除 IBM SOAPElement,那么您就可以在任何應用服務器上使用這些代碼。IBM SOAPElement 內置的性能優化也適用于 Application Server。

    每一個 SOAPElement 都使用 Dom4j 來讀取、解析和轉換。Dom4j 是一種在內存中表示 XML 樹的對象模型。Dom4j 提供了一組易于使用的 API,從而為我們提供了一整套強大的功能來處理、操作或定位 XML,使用 XPath 和 XSLT 進行工作,以及與 SAX、 JAXP、DOM 集成。

    除了可以使用任意的 XML 解析器外,DOM4J 還允許使用任意的 SAX 解析器,為實現更好的性能,還允許使用所有標準的 XSLT 轉換器。 轉換被用來析取發送給 Web Service Appender 的客戶端 LoggingEvent 的元素。

    如果您允許使用 SOAPElement,那么就需要在代碼中維持最大限度的靈活性。Web Service Appender 服務可以被修改,以支持所有發送給服務的 XML。





    回頁首


    輸出

    下面的示例展示了 Web Service Appender 的可能的輸出:

    INFO [WebContainer : 0] ejb.LogAppenderBean (log:?) :: [1111513482641:OO7-64BIT/9.48.114.183:main]LoggingSample instantiation...

    OO7-64BIT/9.48.114.183 是機器名和 IP 地址,而 main 是日志所在處的方法名。





    回頁首


    結束語

    Web Service Appender 是將日志集中到某一位置的基本工具。由于 Web Service Appender 是 Log4j 的 Appender 類的子集,因而配置和使用 Appender 都非常簡單易懂。您可以修改 Log4j 的屬性文件,這樣,使用 Log4j 的現有應用程序和服務就可以馬上使用 Web Service Appender。






    回頁首


    下載

    描述名字大小下載方法
    Foundation Class Libraryfoundation.zip47 KBHTTP
    Logging Web Service J2EE ApplicationLoggingWebService.ear1976 KBHTTP
    Unit Test Sample CodeSoapClientTest.java5 KBHTTP
    posted on 2009-07-15 11:49 禮物 閱讀(696) 評論(0)  編輯  收藏 所屬分類: web serviceLog
    主站蜘蛛池模板: 成人毛片视频免费网站观看| 亚洲日本VA中文字幕久久道具| 日韩亚洲国产二区| 亚洲一区在线免费观看| 免费国产污网站在线观看| 羞羞漫画页面免费入口欢迎你| 亚洲一区二区三区亚瑟| 91天堂素人精品系列全集亚洲| 亚洲大尺度无码无码专区| 国产成人精品日本亚洲专区 | 国产午夜精品理论片免费观看| 免费大片av手机看片| 美女被免费网站视频在线| 亚洲AV无码一区二区三区久久精品| 亚洲熟女www一区二区三区| 亚洲国产日韩综合久久精品| 中文字幕在线观看亚洲视频| 亚洲AV无码久久久久网站蜜桃 | 免费人成激情视频在线观看冫 | 亚洲av无码电影网| 亚洲国产精品嫩草影院| 精品久久亚洲一级α| 成人a毛片免费视频观看| 成人无码视频97免费| 亚在线观看免费视频入口| 6080午夜一级毛片免费看6080夜福利 | 亚洲风情亚Aⅴ在线发布| 免费精品视频在线| 美女网站在线观看视频免费的 | 国产午夜亚洲精品午夜鲁丝片| 亚洲第一AV网站| 亚洲av无码专区在线| 又大又硬又粗又黄的视频免费看 | 日韩一级在线播放免费观看| 久久伊人亚洲AV无码网站| 久久亚洲精品中文字幕无码| 亚洲精品第一综合99久久| 亚美影视免费在线观看| av免费不卡国产观看| www国产亚洲精品久久久| 亚洲av永久无码精品漫画|