- logback 配置
logback的配置方式包括:编程配置、XML文件配置、Groovy文件配置。对于使用log4j的用户,还可以通过logback提供的工具( http://logback.qos.ch/translator/ ) 将log4j.properties配置文件转换为logback.xml格式。
logback 初始化配置的步骤如下:
- 在类路径下依次查找 logback.groovy, logback-test.xml, logback.xml文件;
- 若找到配置文件,则读取文件,配置logback;
- 如果没找到任何配置文件,且JVM包含ServiceLoader(JDK 6以上),则由ServiceLoader解析com.qos.logback.classic.spi.Configurator的实现。
- 如果以上均失败,则使用BasicConfigurator的默认配置,输出日志到控制台。
3、4两步用于在没找到配置文件时提供默认配置。
1.1 logback的默认配置
不提供配置文件,logback使用其默认配置。先给个示例代码:
package chapters.configuration;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class MyApp1 { final static Logger logger = LoggerFactory.getLogger(MyApp1.class);
public static void main(String[] args) { logger.info("Entering application.");
Foo foo = new Foo(); foo.doIt(); logger.info("Exiting application."); } } |
Foo类如下:
package chapters.configuration;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class Foo { static final Logger logger = LoggerFactory.getLogger(Foo.class);
public void doIt() { logger.debug("Did it again!"); } } |
假设类路径下不包含配置文件,logback使用BasicConfigurator的默认配置。该配置root logger使用ConsoleAppender,级别为DBUEG,输出格式PatternLayoutEncoder 的pattern为%d{HH:mm:ss.SSS}[%thread]%-5level%logger{36}-%msg%n。
上例的输出如下:
15:22:09.106 [main] INFO manual.configuration.MyApp1 - Entering application. 15:22:09.121 [main] DEBUG manual.configuration.Foo - Did it again! 15:22:09.121 [main] INFO manual.configuration.MyApp1 - Exiting application. |
MyApp1通过org.slf4j.LoggerFactory和org.slf4j.Logger类和logback连接,除了配置logback的代码(完全可以没有),在代码上没有任何调用logback的类,在编译时依赖slf4j,但不依赖logback,所以很容易移植到其他的日志框架。
1.2 使用logback-test.xml或logback.xml进行配置
下面的XML配置文件等效于BasicConfigurator的默认配置:
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned by default the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration> |
将该文件命名为logback.xml或logback-test.xml放在类路径下,运行MyApp1,可以得出和上面相同的输出。
1.3 出现warning或errors时输出状态信息
如果在解析配置文件时出错,logback会自动将解析错误信息输出到控制台;如果代码里已指定状态监听器,为了避免重复输出,logback会禁用自动输出功能。
下面演示如何主动查询logback的解析状态信息(除了查询内部状态的两行代码,其他和MyApp1完全一致):
public static void main(String[] args) { // 假设SLF4J和logback绑定 LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); // 打印logback的内部状态 StatusPrinter.print(lc); … } |
其输出如下:
15:34:26,052 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy] 15:34:26,052 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml] 15:34:26,052 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml] 15:34:26,052 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Setting up default configuration.
15:34:26.099 [main] INFO chapters.configuration.MyApp2 - Entering application. 15:34:26.114 [main] DEBUG chapters.configuration.Foo - Did it again! 15:34:26.114 [main] INFO chapters.configuration.MyApp2 - Exiting application. |
可以看到,后面的输出和上个例子完全一样,前面的一段输出为logback的内部状态信息。
除了使用StatusPrinter,也在配置文件中设置(前提是配置文件无错),此时没有出错,也能输出logback内部信息。配置方法:将configuration元素的debug属性设置为true,如下所示:
<?xml version="1.0" encoding="UTF-8" ?> <configuration debug="true"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned by default the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration> |
该debug属性只控制logback内部状态数据,对其他不存在任何影响。
1.4 通过系统属性指定默认配置文件位置
使用系统属性"logback.configurationFile"可以指定logback的默认配置文件位置。该属性值可以是URL、类路径下的文件或应用外的文件路径,如下所示:
java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1 |
文件扩展名必须为.xml或.groovy。
1.5 修改后自动重新载入配置文件
logback可以自动扫描配置文件,在配置文件改变时自动重新配置。配置方法:
将configuration的scan属性设置为true:
<configuration scan="true"> … </configuration> |
扫描时间间隔默认1 min 1次,通过configuration的scanPeriod属性可以修改时间间隔:
<configuration scan="true" scanPeriod="30 seconds"> … </configuration> |
NOTE:如果没指定时间单位,默认单位为毫秒
1.6 直接调用JoranConfigurator
logback的配置依赖于Joran库,该库为logback-core的一部分。logback在找到配置文件后会调用JoranConfigurator进行配置,如下所示:
package chapters.configuration;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.util.StatusPrinter;
public class MyApp3 { final static Logger logger = LoggerFactory.getLogger(MyApp3.class);
public static void main(String[] args) { // assume SLF4J is bound to logback in the current environment LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
try { JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(context); // Call context.reset() to clear any previous configuration, e.g. default // configuration. For multi-step configuration, omit calling context.reset(). context.reset(); configurator.doConfigure(args[0]); } catch (JoranException je) { // StatusPrinter will handle this } StatusPrinter.printInCaseOfErrorsOrWarnings(context);
logger.info("Entering application.");
Foo foo = new Foo(); foo.doIt(); logger.info("Exiting application."); } } |
先获得当前起作用的LoggerContext,然后创建JoranConfigurator实例,设置其作用的context实例,重置context,然后载入配置文件进行配置。
1.7 查看状态信息
logback的内置状态数据保存在StatusManager对象中,通过LoggerContext可以获得。
为了节省内存,StatusManager将状态信息分两部分保存:header部分和tail部分。header部分保存前H个信息,tail部分保存后T个信息,H=T=150。
logback-classic里一个称为ViewStatusMessagesServlet的服务器。该服务器以HTML表格的形式打印StatusManager的内容,如下所示:
将下面的内容添加到WEB-INF/web.xml文件,可以将该服务器添加到网络应用:
<servlet> <servlet-name>ViewStatusMessages</servlet-name> <servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>ViewStatusMessages</servlet-name> <url-pattern>/lbClassicStatus</url-pattern> </servlet-mapping> |
1.8 监听状态信息
给StatusManager添加StatusListener监听器,能实时监控状态信息,特别是logback配置之后的信息。logback自带的StatusListener的实现称作OnConsoleStatusListener,即,将所有的状态信息打印到控制台。
下面演示为StatusManger注册OnConsoleStatusListener的实例:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); StatusManager statusManager = lc.getStatusManager(); OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener(); statusManager.add(onConsoleListener); |
监听器只输出监听器注册后的信息,所以将监听器放在配置文件最前面比较合适(而且可以在一个配置文件中注册多个监听器),配置方法如下:
<configuration debug="false"> <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" /> … the rest of the configuration file </configuration> |
1.9 停止 logback-classic
通过停止logback context,可以释放logback-classic占用的资源。停止context会关闭所有和对应logger连接的appender,并停止对应的线程:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); lc.stop(); |
对网络应用,则调用ServletContextListener的contextDestroyed方法。
- 配置文件语法
如上图所示,XML配置文件根元素为<configuration>,可以包含[0,∞)个<appender>,[0,∞)个<logger>以及[0,1]个<root>元素。
<logger>
属性:
属性名 | 类型 | Use | 描述 |
name | string | 必须 |
|
additivity | bool | 可选 | 是否向上级logger传递信息,默认为true |
level | string | 可选 | TRACE,DEBUG,INFO,WARN,ERROR,ALL,OFF,不区分大小写,另有额外的两个值:INHERITED或NULL,表示从父logger继承。 |
子元素:
元素名 | minOccurs | maxOccurs | 描述 |
appender-ref | 0 | unbounded | 表示将对应的appender添加到该logger |
<root>
用于配置root logger。root logger为特殊类型的logger,因为root logger名恒为"ROOT",所以无name属性,additivity对其无效,所以只剩下一个属性需要配置:level。其可用值为:TRACE,DEBUG,INFO,WARN,ALL,OFF,不能为INHERITED或NULL。
类似于<logger>,<root>可以包含0或多个<appender-ref>。
实例:假如不想看到"chapters.configuration"包中任何DEBUG信息,如下
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned by default the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender>
<logger name="chapters.configuration" level="INFO" />
<!-- 严格的说,下面的level属性是不需要的,因为root的默认值为DEBUG --> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root>
</configuration> |
包"chapters.configuration"的level属性设置为"INFO",这样DEBUG信息均被过滤掉了。如果将该配置文件作为参数传递给MyApp3,其输出如下:
20:59:32.913 [main] INFO chapters.configuration.MyApp3 - Entering application. 20:59:32.917 [main] INFO chapters.configuration.MyApp3 - Exiting application. |
此时由"chapters.configuration.Foo"生成的DEBUG信息被抑制。
可以按照自己的想法随意设置多个logger的level,比如,将chapters.configuration 包设置INFO,单独把Foo设置为DEBUG,如下所示:
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned by default the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <logger name="chapters.configuration" level="INFO" /> <logger name="chapters.configuration.Foo" level="DEBUG" /> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration> |
用该文件作为参数运行MyApp3,输出如下:
21:16:56.913 [main] INFO chapters.configuration.MyApp3 - Entering application. 21:16:56.915 [main] DEBUG chapters.configuration.Foo - Did it again! 21:16:56.916 [main] INFO chapters.configuration.MyApp3 - Exiting application. |
下面列出上面各个logger对应的level:
Logger 名 | 指定的 Level | 实际的 Level |
root | DEBUG | DEBUG |
chapters.configuration | INFO | INFO |
chapters.configuration.MyApp3 | null | INFO |
chapters.configuration.Foo | DEBUG | DEBUG |
由此可见,MyApp3的INFO和Foo.doIt()的DEBUG都启用了。而root logger总是为非NULL的,其默认值为DEBUG。
<appender>
<appender>用于配置日志输出位置。属性:
属性名 | 类型 | Use | 描述 |
name | string | required | appender名,可随意取 |
class | string | required | appender对应的类,需包含完整路径,如输出到console对应的:class="ch.qos.logback.core.ConsoleAppender" |
子元素:
元素名 | minOccurs | maxOccurs |
layout | 0 | 1 |
encoder | 0 | unbounded |
filter | 0 | unbounded |
layout
layout元素必须包含class元素,包含layout类的完全限定名。
<configuration> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>myApp.log</file> <!-- encoders are assigned by default the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern> </encoder> </appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="FILE" /> <appender-ref ref="STDOUT" /> </root> </configuration> |
2.6 定义变量
可以在配置文件中定义变量,也可以从外部导入。在logback的XML配置文件中可以用<property>和<variable>(1.07之后)定义变量。下面定义一个变量,用于定义输出文件位置:
<configuration> <property name="USER_HOME" value="/home/sebastien" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="FILE" /> </root> </configuration> |
也可以用系统变量达到相同的目的:
java -DUSER_HOME="/home/sebastien" MyApp2 |
然后在配置文件中引用该变量:
<configuration> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="FILE" /> </root> </configuration> |
如果需要很多变量,则以一个单独的文件存放所有变量比较合适:
下面的配置文件引用了一个变量:
<configuration> <property file="src/main/java/chapters/configuration/variables1.properties" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="FILE" /> </root> </configuration> |
该文件包含variables1.properties属性文件的引用。属性文件中定义的变量会被作为本地变量引入,variable.properties文件格式如下:
USER_HOME=/home/sebastien |
也可以直接引用类路径下的文件:
<configuration> <property resource="resource1.properties" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="FILE" /> </root> </configuration> |
作用域
还可以对上面定义的变量进行作用域限制,local, context或system,分别对应配置范围,logback程序范围及JVM范围,定义方式如下:
<configuration> <property scope="context" name="nodeId" value="firstNode" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>/opt/${noteId}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender>
<root level="debug"> <appender-ref ref="FILE" /> </root> </configuration> |
scope可用值有:local, context 和 system。
默认值
假设变量名为aName,指定其默认值为golder,指定语法为:"${aName:-golden}"。
嵌套变量
嵌套指一个变量可以引用另一个变量。包括值嵌套、名嵌套以及默认值嵌套。
值嵌套
USER_HOME=/home/sebastien fileName=myApp.log destination=${USER_HOME}/${fileName} |
destination变量值包含对USER_HOME变量值和fileName变量值的引用。
名嵌套
当引用一个变量时,变量名可能包含对其他变量的引用。例如,如果变量"userid"的值为"alice",则"${${userid}.password}"表示名为"alice.password"的变量。
默认值嵌套
如变量"id"未分配值,变量"userid"值为"alice",则"${id:-${userid}}"