打造一个基于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类的第几行输出的,不知道各位大虾是否有人知道该如何解决呢,希望不吝赐教:)

你可能感兴趣的:(apache,eclipse,Web,log4j,osgi)