使用 logback + slf4j 进行日志记录
此处主要介绍maven web工程下如何使用 logback + slf4j 进行日志记录。
logback主要包含三个组成部分:Loggers(日志记录器)、Appenders(输出目的在)、Layouts(日志输出格式)
slf4j :如jdbc一样,定义了一套接口,是一个日志门面,可实现多个日志系统间快速切换(通过修改配置文件)
logback : 和log4j是同一作者,是log4j的升级版,效果可想而知.
logback 主要分为三个模块,分别是:
logback-core:提供基础功能,是其他两个模块的基础
logback-classic : log4j的升级,实现了self4j api
logback-access:用于与sevlet容器进行集成、提供网络访问日志的功能
logback初始化时,默认会去classpath下依次加载如下配置文件(logback.groovy、logback-test.xml、logback.xml),当找不到配置文件时logback将为rootLogger 添加一个 ConsoleAppender ,用于将日志输出到控制台。对于logback的初始化,官网有如下描述
Logback tries to find a file called logback.groovy in the classpath.
If no such file is found, logback tries to find a file called logback-test.xml in the classpath.
If no such file is found, it checks for the file logback.xml in the classpath..
If no such file is found, service-provider loading facility (introduced in JDK 1.6) is used to resolve the implementation of com.qos.logback.classic.spi.Configurator interface by looking up the file META-INF\services\ch.qos.logback.classic.spi.Configurator in the class path. Its contents should specify the fully qualified class name of the desired Configurator implementation.
If none of the above succeeds, logback configures itself automatically using the BasicConfigurator which will cause logging output to be directed to the console.
编程时可是要如下代码查看logback内部运行情况:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);
对于web项目,可配置sevlet,然后通过网页查看logback内部运行状态,如下:
<!-- 通过浏览器以html形式查看logback内部状态 :http://host/yourWebapp/lbClassicStatus --> <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>
说了一大堆废话,现在开始进入主题:
首先,在pom文件引入相关依赖,如下:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.13</version> </dependency>
接着,编写logback.xml(位于classpath目录下,此处为src/main/resources目录)
<?xml version="1.0" encoding="UTF-8"?> <!--debug="true" : 打印logback内部状态(默认当logback运行出错时才会打印内部状态 ),配置该属性后打印条件如下(同时满足): 1、找到配置文件 2、配置文件是一个格式正确的xml文件 也可编程实现打印内部状态,例如: LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); StatusPrinter.print(lc); --> <!-- scan="true" : 自动扫描该配置文件,若有修改则重新加载该配置文件 --> <!-- scanPeriod="30 seconds" : 配置自动扫面时间间隔(单位可以是:milliseconds, seconds, minutes or hours,默认为:milliseconds), 默认为1分钟,scan="true"时该配置才会生效 --> <configuration debug="false" scan="true" scanPeriod="30 seconds" packagingData="true"> <!-- 设置 logger context 名称,一旦设置不可改变,默认为default --> <contextName>myAppName</contextName> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder --> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 当前活动日志文件名 --> <file>./my_log.log</file> <!-- 文件滚动策略根据%d{patter}中的“patter”而定,此处为每天产生一个文件 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 归档文件名“.zip或.gz结尾”,表示归档文件自动压缩 --> <FileNamePattern>./my_log%d{yyyyMMdd}.log.zip</FileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <!--rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>renhai%i.log</fileNamePattern> <minIndex>1</minIndex> <maxIndex>10</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>20MB</maxFileSize> </triggeringPolicy--> <!-- <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> rollover daily <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.log</fileNamePattern> each file should be at most 30MB, keep 60 days worth of history, but at most 20GB <maxFileSize>30MB</maxFileSize> <maxHistory>60</maxHistory> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> --> <encoder> <pattern>%d{HH:mm:ss.SSS}[%-5level][%thread]%logger{36} - %msg%n</pattern> <!-- <pattern>%d{HH:mm:ss.SSS}[%-5level][%thread] - %msg%n</pattern> --> </encoder> </appender> <!-- 日志级别若没显示定义,则继承最近的父logger(该logger需显示定义level,直到rootLogger)的日志级别--> <!-- logger的appender默认具有累加性(默认日志输出到当前logger的appender和所有祖先logger的appender中),可通过配置 “additivity”属性修改默认行为--> <logger name="com.yinz" level="debug" additivity="false" > <appender-ref ref="FILE"/> </logger> <!-- 至多只能配置一个root --> <root level="debug"> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> </configuration>
最后,就可以在程序中使用logback了,例如:
package com.yinz.aaa; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Test { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Test.class); logger.debug("test........"); } }
如上所述,我们使用的slf4j中的api,如此依赖,要想在多个日志系统间切换,只需要提供相应的配置文件就可以了,而不需要修改编码部分。
最后有几点需要注意:
1、logger 的日志级别若没显示定义,则继承最近的祖先logger(该logger需显示定义level,直到rootLogger)的日志级别。
1.1,、logger的父子关系,由logger的名称决定,例如有三个logger,分别为:java.lang.util 、 java.lang 、java
则,java是java.lang的父logger, 是java.lang.util的祖先logger. 而同时java.lang是java.lang.util的父logger
2、logger的appender默认具有累加性(默认日志输出到当前logger的appender和所有祖先logger的appender中),可通过配置 “additivity”属性修改默认行为