先看一个配置文件例子,logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<contextName>logback</contextName>
<springProfile name="test"><!-- 如果不同环境日志存放路径相同,无需套上springProfile节点 -->
<property name="log.path" value="D:\\test\\" />
</springProfile>
<springProfile name="prod">
<property name="log.path" value="D:\\prod\\" />
</springProfile>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n </pattern>
</encoder>
</appender>
<!-- 不带过滤器,能记录所有级别的日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.path}/info.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 通常情况下,日志按天分割,如:${log.path}/info-%d{yyyyMMdd}.%i.log -->
<fileNamePattern>${log.path}/info-%d{yyyy-MM-dd_HH-mm}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n </pattern>
</layout>
</appender>
<!-- error级别的文件输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<File>${log.path}/error.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error-%d{yyyy-MM-dd_HH-mm}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n </pattern>
</layout>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<springProfile name="dev">
<logger name="com" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
</springProfile>
<springProfile name="test,prod">
<logger name="com" level="INFO" additivity="false">
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
</logger>
</springProfile>
</configuration>
1、其中springProfile可以在Spring的xml文件中配置,如果是spring boot,可以在application.properties中配置,配置如下(更多有关profile内容可看Spring Boot学习笔记):
spring.profiles.active=prod
2、logger{n}中的n代表logger的长度,logger指的是LoggerFactory.getLogger(Xxx.class)中的Xxx的包类名,长度>n时,从左边的包开始,只取包的首字母,直到<=n,还要满足下面两个要求:
1)不管是否满足长度要求,至少保留包的首字母,n为0除外
2)不管是否满足长度要求,类名一定要是全名,如n=1时,打印c.w.c.UserInfoController,n=0时,打印UserInfoController,n=23时,打印c.w.controller.UserInfoController,n=24时也打印c.w.controller.UserInfoController(假设w是wdy的首字母),直到n=25时,打印c.wdy.controller.UserInfoController。
不带{n}时,代表长度无限制,打印整个包类名。
%logger获取的是我们在java代码中手动设置的包类名,我们也可以在运行中动态获取包类名、方法名及行号
%class.%method :%line({n}也可以用于class,如%class{0})
下面是一个常见的日志格式:
%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%-14.14thread] %-30.30logger{30} [%-20.20method]:%-4line- %msg%n
说明:
1、%-5level:level代表日志级别,-5代表如果日志级别长度小于5,则右边补齐空格,如,INFO,则右边补一个空格;
2、%-14.14thread:thread代表线程名字,-14代表长度小于14时则右边补齐空格,另一个14代表最长长度,如果名字长度大于14,则截掉名字左边,如abcdefghijklmnopq,则输出defghijklmnopq,当然也可以用%-14.20thread,只是这样就不能很好对齐而已,因为,补齐的时候只补齐到长度为14;
3、%-30.30logger{30} :{30}会先起作用,其作用上面已经说过了,另外两个30再做截取和补齐,当然这三个值随便取,不要求相同。
注意:
在日志模式中指定(动态获取)类名、方法名以及行号会带来严重的性能问题。
下面开始具体节点配置学习
1、configuration
1)、自动扫描重新加载变更的配置文件
默认情况下,配置文件每分钟会被扫描一次看是否被修改,我们也可以自定义扫描的周期或关闭扫描,默认情况下时间单位是毫秒,如:
<configuration scan="true" scanPeriod="30 seconds" >
...
</configuration>
值得注意的是,下面的设置不能被动态修改,即属性值不能被修改:
<property name="log.path" value="D:\\log\\test\\" />
2)、打印栈信息中每行所属的包(jar)信息
默认情况下不打印包信息,可以通过以下设置开启该功能:
<configuration packagingData="true">
...
</configuration>
打印信息如:
14:28:48.835 [btpool0-7] INFO c.q.l.demo.prime.PrimeAction - 99 is not a valid value java.lang.Exception: 99 is invalid at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na] at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9] at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9] at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]
也可以通过java代码开启:
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.setPackagingDataEnabled(true);
configuration节点除了有很多可以配置的属性之外,还有下面三个子节点可以配置:
1、appender,0个至多个,用于声明日志的输出方式(控制台、文件,其中文件也有多种方式)、输出格式、过滤条件等
2、logger,0个至多个,可以声明日志级别,通过0个至多个appender-ref节点与appender关联
3、root,有且仅有一个,是一个特殊的logger
2、appender
1)、appender节点可以包含一个layout或encoder子节点,子节点中可以再包含一个pattern子节点,用来设置日志输出格式。
2)、appender节点有name、class属性,class是Appender接口的实现类的包类名,Appender实现类关系如下图:
ConsoleAppender用于输出到控制台,RollingFileAppender用于输出到文件。
通过类图可以看到,如果是输出到文件,则可以设置File、Append、rollingPolicy、triggeringPolicy等。
rollingPolicy常用的实现类有:TimeBasedRollingPolicy、SizeAndTimeBasedRollingPolicy和FixedWindowRollingPolicy。
triggeringPolicy常用的实现类有:SizeBasedTriggeringPolicy。
可以给上面的Appender套上一层异步日志Appender,如:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myapp.log</file>
<encoder>
<pattern>%logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<root level="INFO">
<appender-ref ref="ASYNC" />
</root>
</configuration>
测试的时候发现一个问题,使用异步日志的时候,%method和%line会返回“?”。比较奇怪的是,如果在写异步日志前,先采用非异步日志写文件或写到控制台,这时就不会出现“?”的情况。
继续补充异步日志
写自己的Appender。。。。。。
官方文档
https://logback.qos.ch/manual/index.html