OSGi教程 – 10 – 使用日志服务
日志服务几乎是所有系统的必备组件,近年来大家使用得最多的应该是Log4j及其替代者Logback。但很有意思的是在OSGi环境中如何使用日志服务,却缺乏很明确的说法,甚至需要查阅大量英文资料甚至源码。本章将为你解决此问题,并且会提出几种不同的解决方案。
10.1 使用Log4j日志组件
Log4j几乎已经成为了Java日志系统的业界标准,不过需要注意的是在2015年8月,Log4j官方已经宣布Log4j 1.X已经不再继续开发,已经开始推动Log4j 2,在系统架构、性能等方面做了大幅升级。目前主流使用的是Lo4j 1.2,包括目前Eclipse IDE中使用的也是此版本,本文也以此版本作为样例。
10.1.1 创建OSGi框架配置
首先参考以前的章节,进入菜单“Run->Run Configurations…”,新建一个名为log4j的OSGi Framework,如下图:
确保如下几个Bundle是被勾选的:
- eclipse.osgi
- eclipse.osgi.services
- eclipse.equinox.event
- eclipse.equinox.ds
- apache.felix.gogo.command
- apache.felix.gogo.runtime
- apache.felix.gogo.shell
- eclipse.equinox.console
- eclipse.equinox.util
- apache.log4j
10.1.2 创建Log4j的配置文件Fragment Bundle
使用Log4j需要编写配置文件,并确保Log4j库及其配置文件能被正确加载。之前的章节已经介绍过,Fragment Bundle与其Host Bundle处于同一ClassPath中,因此可以考虑创建Log4j Bundle的Fragment Bundle,将Log4j配置文件放到该Fragment Bundle中。
创建个名为Log4jXML的Fragment Project,如下图:
确保该Fragment Bundle的Host Plugin为log4j,如下图:
创建如下配置文件log4j.xml(Log4j配置文件的写法及其配置介绍不在本文讨论范围内,请读者自行查阅资料),并将其存放到该项目的根目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' > <appender name="console" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{yyyyMMdd HH:mm:ss SSS\} %-5p] %l - %m%n" /> </layout> </appender> <appender name="file" class="org.apache.log4j.RollingFileAppender"> <param name="File" value="D:/filetest.log" /><!-- 设置日志输出文件名 --> <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 --> <param name="Append" value="true" /> <param name="MaxBackupIndex" value="10" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="[%d{yyyyMMdd HH:mm:ss SSS\} %-5p] [%t] %l - %m%n" /> </layout> </appender> <!-- 根logger的设置--> <root> <priority value ="debug"/> <appender-ref ref="console"/> <appender-ref ref="file"/> </root> </log4j:configuration> |
10.1.3 创建测试Bundle
为了测试Log4j是否可以正常工作,我们可以创建一个名为Log4jXMLTest的测试Bundle,如下图:
选择Next按钮后,注意勾选Options下面的Generate an activator选项,如下图:
选择Next按钮后,选择“Hello OSGi Bundle”作为模板,如下图:
双击MANIFEST.MF文件,在打开的编辑器视图中的Dependencies选项卡中添加Imported Packages,确保org.apache.log4j和org.osgi.framework这两个包被添加完毕,如下图:
参考下面的代码段,修改Activator类代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import org.apache.log4j.Logger; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { System.out.println("Hello World!!"); Logger logger = Logger.getLogger(Activator.class); logger.info("Info starting"); logger.warn("Warning starting"); logger.error("Error starting"); } public void stop(BundleContext context) throws Exception { System.out.println("Goodbye World!!"); } } |
Log4j的使用不在本文的讨论范围之类,读者可自行查阅相关资料。在上面的代码段中,红色粗体字的代码即调用Log4j包的核心代码,在你自己的代码中,可以模仿编写对应代码。
10.1.4 运行测试
从菜单“Run->Run Configration”或工具栏上的绿色运行图标进入运行菜单,运行名为log4j的OSGi Framework,如下图:
如果运行正确,在控制台上将看到如下输出,并且在文件D:/filetest.log中也会看到相关日志:
此时的工作空间如下图所示,如果你的所有步骤正确,应该也和我的工作空间类似,Good Luck!
10.2 使用SLF4j和Log4j日志组件
SLF4j是(Simple Logging Facade for Java)的简称,它不是一个真正的日志实现,而是为java.util.logging、Apache log4j、logback等日志实现了一个抽象层,使得上层应用能以统一的方式来编写日志代码,使你的代码不依赖于具体的日志实现,它已经是事实上的Java世界的日志标准。
本节我们将结合SLF4j来Log4j,因此在学习本节之前,请先学习前一节的内容。
10.2.1 创建OSGi框架配置
首先参考以前的章节,进入菜单“Run->Run Configurations…”,新建一个名为SLF4j_log4j的OSGi Framework,如下图:
确保如下几个Bundle是被勾选的:
- eclipse.osgi
- eclipse.osgi.services
- eclipse.equinox.event
- eclipse.equinox.ds
- apache.felix.gogo.command
- apache.felix.gogo.runtime
- apache.felix.gogo.shell
- eclipse.equinox.console
- eclipse.equinox.util
- apache.log4j
- slf4j.api
- slf4j.impl.log4j12
注意:最后红色字体标出的Bundle替代了上一节的org.apache.log4j
10.2.2 创建Log4j的配置文件Fragment Bundle
可以参考上一节创建Log4j的配置文件Fragment Bundle,这里我们继续使用之前创建的Log4jXML工程,此处不再赘述。请确保在Run Configurations窗体中勾选对应的项目。
10.2.3 创建测试Bundle
参考上一节创建测试名为SLF4jTest的测试Bundle,创建完毕后,双击MANIFEST.MF文件,在打开的编辑器视图中的Dependencies选项卡中添加Imported Packages,确保org.slf4j和org.osgi.framework这两个包被添加完毕,如下图:
参考下面的代码段,修改Activator类代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { Logger logger=LoggerFactory.getLogger(Activator.class); logger.info("Info starting"); logger.warn("Warning starting"); logger.error("Error starting"); } public void stop(BundleContext context) throws Exception { System.out.println("Goodbye World!!"); } } |
注意:红色粗体代码部分,与上一节已经有所不同,由依赖Log4j包变成了依赖SLF4j相关包,也就是说上层应用代码已经与日志实现Log4j相关包解耦了。
10.2.4 运行测试
从菜单“Run->Run Configration”或工具栏上的绿色运行图标进入运行菜单,运行名为SLF4j+log4j的OSGi Framework,如下图:
如果运行正确,在控制台上将看到如下输出,并且在文件D:/filetest.log中也会看到相关日志:
此时的工作空间如下图所示:
如果你的所有步骤都正确,应该也和我的工作空间类似,Good Luck(注意和上一节未使用SLF4j时的情况进行对比,关闭或移除多余的Log4jXMLTest工程)!
10.3 使用SLF4j和Logback日志组件
Logback也是由log4j的创始人编写的,它是log4j的一个改良版本,从目前的情况来看,在某些应用场景中log4j1.X确实会比Logback性能差很多,而据称log4j2已经与logback相当。
本节将会使用Logback替代Log4j实现,由于使用了SLF4j,因此上层代码不用改变,因此本节将复制之前创建的SLF4jLog4jTest工程直接作为测试代码。
10.3.1 创建OSGi框架配置
首先参考以前的章节,进入菜单“Run->Run Configurations…”,新建一个名为SLF4j_Logback的OSGi Framework,如下图:
确保如下几个Bundle是被勾选的:
- eclipse.osgi
- eclipse.osgi.services
- eclipse.equinox.event
- eclipse.equinox.ds
- apache.felix.gogo.command
- apache.felix.gogo.runtime
- apache.felix.gogo.shell
- eclipse.equinox.console
- eclipse.equinox.util
- apache.log4j
- slf4j.api
- qos.logback.slf4j
- qos.logback.core
- qos.logback.classic
注意:最后红色字体标出的Bundle替代了上一节的org.apache.log4j相关内容
10.3.2 创建Logback的配置文件Fragment Bundle
与使用Log4j类似,使用Logback同样需要编写配置文件,并确保它能被正确加载,因此可以考虑创建Logback Bundle的Fragment Bundle,将配置文件放到该Fragment Bundle中。
参考前面的章节建立ch.qos.logback.classic的Fragment Bundle,具体步骤这里不再赘述,创建完毕后在其根目录下创建配置文件logback.xml,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<?xml version="1.0"?> <configuration> <!-- ch.qos.logback.core.ConsoleAppender 控制台输出 --> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n </pattern> </encoder> </appender> <!-- ch.qos.logback.core.rolling.RollingFileAppender 文件日志输出 --> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <Encoding>UTF-8</Encoding> <File>d:/test.log</File> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>test-%d{yyyy-MM-dd}.log </FileNamePattern> <MaxHistory>10</MaxHistory> <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <MaxFileSize>5MB</MaxFileSize> </TimeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n </pattern> </layout> </appender> <!-- 日志级别 --> <root> <!-- 定义了ERROR和INFO级别的日志,分别在FILE文件和控制台输出 --> <level value="error" /> <level value="info" /> <appender-ref ref="file" /> <appender-ref ref="console" /> </root> </configuration> |
对于Logback配置文件的解析不在本文的范围之内,请大家自行查阅相关资料。如果使用上述配置文件,则在日志组件生效时,会在控制台和D:/test.log文件中输出日志。
创建完毕后,工作空间应该类似如下图所示:
10.3.3 创建测试Bundle
上节中已经提到,SLF4j使得上层应用代码与实际日志实现解耦,因此日志组件的测试可以直接使用上次创建的SLF4jTest工程,无需重新创建。
10.3.4 运行测试
从菜单“Run->Run Configration”或工具栏上的绿色运行图标进入运行菜单,运行名为SLF4j+Logback的OSGi Framework,如下图:
如果运行正确,在控制台上将看到如下输出,并且在文件D:/ test.log中也会看到相关日志:
此时的工作空间如下图所示:
如果你的所有步骤都正确,应该也和我的工作空间类似,Good Luck!
资源下载


SLF4J+Logback章节用的Host Plug-in应该为ch.qos.logback.core
SLF4J Logback章节用的Host Plug-in应该为ch.qos.logback.core
我使用的ch.qos.logback.classic没有问题
我最近打算买个山地.代步吧.应该会远行个几百公里.想买3000左右的装装13.又觉得浪费了1000多的够用了 生活愿景 没钱 没时间..蛋疼