打造一個基於OSGi的Web Application——增加日誌輸出功能

到目前爲止,我們的基於OSGi內核的Web Application還沒有任何的日誌輸出功能,本章將介紹如何在這個Web應用中配置和輸出日誌。

在前面的配置中,我們的應用中只含有commons-logging.jar,而OSGi容器之外的代碼中,均是通過配置commons logging的Log對象來輸出日誌的,在默認的配置下,系統將採用Jdk14Logger來作爲輸出日誌的實現,這對我們來說是遠遠不夠的。我們下一步將配置更加常用的Log4j在作爲我們的日誌輸出實現,通過以下幾個步驟:

一、爲Web Application配置Log4j:
  1.在OSGi-Web項目的Java EE Module Dependencies中,增加對log4j.jar的依賴關係。
  2.在WEB-INF/config目錄中,增加一個log4j.properties文件,內容如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 1  ### direct log messages to stdout ###
 2  log4j.appender.stdout = org.apache.log4j.ConsoleAppender
 3  log4j.appender.stdout.Target = System.out
 4  log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
 5  log4j.appender.stdout.layout.ConversionPattern =% d{ABSOLUTE}  % 5p  % c{ 1 }: % -   % m % n
 6  
 7  #Default Log File Configuration For OSGi
 8  log4j.appender.OSGiLog = org.apache.log4j.DailyRollingFileAppender
 9  log4j.appender.OSGiLog.DatePattern = ' . ' yyyy - MM - dd
10  log4j.appender.OSGiLog.File = ${osgi.root} / logs / OSGi.log
11  log4j.appender.OSGiLog.layout = org.apache.log4j.PatternLayout
12  log4j.appender.OSGiLog.layout.ConversionPattern =% d [ % t]  %- 5p  % -   % m % n
13  
14  log4j.rootLogger = info, stdout
15  
16  log4j.logger.org.dbstar = debug, OSGiLog
17  log4j.logger.org.eclipse = debug, OSGiLog

  3.採用Spring Web的Log4j配置方式,在web.xml中增加如下配置:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 1       <!--  Log4j configuration  -->
 2       < context-param >
 3           < param-name > webAppRootKey </ param-name >
 4           < param-value > osgi.root </ param-value >
 5       </ context-param >
 6       < context-param >
 7           < param-name > log4jConfigLocation </ param-name >
 8           < param-value > /WEB-INF/config/log4j.properties </ param-value >
 9       </ context-param >
10      
11       <!--  Init log4j  -->
12       < listener >
13           < listener-class > org.springframework.web.util.Log4jConfigListener </ listener-class >
14       </ listener >

  4.在OSGi-Web項目的Java EE Module Dependencies中,增加spring相關jar的依賴。

經過以上4個步驟,我們在Web Application中使用commons logging輸出的日誌,都可以通過Log4j來顯示了。但是作爲OSGi容器內部來說,這還不夠。OSGi規範中推薦使用org.osgi.service.log包中的LogService和LogReaderService來管理和顯示OSGi日誌。爲了能正常顯示OSGi容器內部的日誌,我們還需要將LogService、LogReaderService和OSGi容器外部的Log4j結合起來才行,爲了達到這個目的,我們還需要做以下幾個步驟:
  1.爲OSGi容器增加一個org.osgi.service.log的實現包。在equinox-SDK-3.6M5開發包中,這個實現jar是:org.eclipse.equinox.log_1.2.100.v20100118.jar,當然,還需要org.eclipse.osgi.services_3.2.100.v20100108.jar,都放置到OSGi-Web工程的WEB-INT/osgi/plugins目錄下面。
  2.爲OSGi容器增加Declarative Services支持。在equinox-SDK-3.6M5開發包中,包含了一個DS的實 現:org.eclipse.equinox.ds_1.2.0.v20100125.jar,將這個jar和一個依賴的 jar:org.eclipse.equinox.util_1.0.100.v20090520-1800.jar部署到OSGi容器中,就可以使用 DS服務了。同樣也放到plugins目錄下面去。
  3.新增一個plugin工程,名字爲:org.dbstar.osgi.log,我們使用DS方式來獲取服務,相關源代碼如下:
    OSGI-INF/log.xml

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->1  <? xml version="1.0" encoding="UTF-8" ?>
2  < scr:component  xmlns:scr ="http://www.osgi.org/xmlns/scr/v1.1.0"  enabled ="true"  name ="logListener"  xsi:schemaLocation ="http://www.osgi.org/xmlns/scr/v1.1.0 http://www.osgi.org/xmlns/scr/v1.1.0/scr.xsd" >
3     < implementation  class ="org.dbstar.osgi.log.LogListenerImpl" />
4     < reference  cardinality ="1..1"  interface ="org.osgi.service.log.LogReaderService"  name ="LogReaderService"  policy ="static" />
5  </ scr:component >

    LogListenerImpl.java

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 1  package  org.dbstar.osgi.log;
 2  
 3  import  org.apache.commons.logging.Log;
 4  import  org.apache.commons.logging.LogFactory;
 5  import  org.osgi.service.component.ComponentContext;
 6  import  org.osgi.service.log.LogEntry;
 7  import  org.osgi.service.log.LogListener;
 8  import  org.osgi.service.log.LogReaderService;
 9  import  org.osgi.service.log.LogService;
10  
11  public   class  LogListenerImpl  implements  LogListener {
12       private   static   final  Log logger  =  LogFactory.getLog(LogListenerImpl. class );
13  
14       protected   void  activate(ComponentContext context) {
15          LogReaderService service  =  (LogReaderService) context.locateService( " LogReaderService " );
16          service.addLogListener( this );
17      }
18  
19       protected   void  deactivate(ComponentContext context) {
20          LogReaderService service  =  (LogReaderService) context.locateService( " LogReaderService " );
21          service.removeLogListener( this );
22      }
23  
24       public   void  logged(LogEntry entry) {
25          String msg  =  getMessage(entry);
26  
27           switch  (entry.getLevel()) {
28           case  LogService.LOG_DEBUG:
29               if  (logger.isDebugEnabled()) {
30                   if  (entry.getException()  ==   null ) {
31                      logger.debug(msg);
32                  }  else  {
33                      logger.debug(msg, entry.getException());
34                  }
35              }
36               break ;
37           case  LogService.LOG_INFO:
38               if  (logger.isInfoEnabled()) {
39                   if  (entry.getException()  ==   null ) {
40                      logger.info(msg);
41                  }  else  {
42                      logger.info(msg, entry.getException());
43                  }
44              }
45               break ;
46           case  LogService.LOG_WARNING:
47               if  (logger.isWarnEnabled()) {
48                   if  (entry.getException()  ==   null ) {
49                      logger.warn(msg);
50                  }  else  {
51                      logger.warn(msg, entry.getException());
52                  }
53              }
54               break ;
55           case  LogService.LOG_ERROR:
56               if  (logger.isErrorEnabled()) {
57                   if  (entry.getException()  ==   null ) {
58                      logger.error(msg);
59                  }  else  {
60                      logger.error(msg, entry.getException());
61                  }
62              }
63               break ;
64          }
65      }
66  
67       private  String getMessage(LogEntry entry) {
68          StringBuilder msg  =   new  StringBuilder();
69           if  (entry.getBundle()  !=   null ) msg.append( " [bundle: " ).append(entry.getBundle()).append( " ] " );
70           if  (entry.getServiceReference()  !=   null ) msg.append( " [service: " ).append(entry.getServiceReference())
71                  .append( " ] " );
72          msg.append(entry.getMessage());
73           return  msg.toString();
74      }
75  }

    META-INF/MANIFEST.MF

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 1  Manifest-Version:  1.0
 2  Bundle-ManifestVersion:  2
 3  Bundle-Name: Log Bundle
 4  Bundle-SymbolicName: org.dbstar.osgi.log
 5  Bundle-Version:  1.0.0
 6  Bundle-Vendor: dbstar
 7  Bundle-RequiredExecutionEnvironment: J2SE- 1.5
 8  Service-Component: OSGI-INF/log.xml
 9  Import-Package: org.apache.commons.logging ; version="1.0.4",
10   org.osgi.framework ; version="1.3.0",
11   org.osgi.service.component ; version="1.1.0",
12   org.osgi.service.log ; version="1.3.0"

好了,打包成bundle jar然後也扔到plugins目錄下面,然後clean一下server,啓動,現在能看到多了許多日誌輸出,現在OSGi內部通過LogService輸出的日誌也能由Log4j接管了。

最後總結一下,LogService和LogReaderService是OSGi規範中提倡的日誌標準,在equinox內部實現中大量使用了這種日誌,而commons logging是我們開發常規程序時所常用的日誌方式。在你的bundle代碼中,具體要採用哪一種日誌方式,並沒有強制的要求,大家可以根據各人喜好來選用。
順便提一句,LogService有些美中不足的是,不能像commons logging那樣,顯示出日誌具體是從哪個java類的第幾行輸出的,不知道各位大蝦是否有人知道該如何解決呢,希望不吝賜教:)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章