打造一个基于OSGi的Web Application——增加日志输出功能

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

你可能感兴趣的:(打造一个基于OSGi的Web Application——增加日志输出功能)