引言
大约从16年,不管是我参与别人已搭建好的项目还是自己单独搭建的项目,日志框架基本都换成了logback。
# logback优点
- 内核重写、测试充分、初始化内存加载更小,这一切让logback性能和log4j相比有诸多倍的提升
- logback非常自然地直接实现了slf4j,这个严格来说算不上优点,只是这样,再理解slf4j的前提下会很容易理解logback,也同时很容易用其他日志框架替换logback
- logback有比较齐全的文档
- logback当配置文件修改了,支持自动重新加载配置文件,扫描过程快且安全,它并不需要另外创建一个扫描线程
- 支持自动去除旧的日志文件,可以控制已经产生日志文件的最大数量
配置的正确姿势
我们大部分Java后台都是Maven工程,标准目录如下:
包路径 |
说明 |
src/main/java |
java源代码文件,编译到target/classes |
src/main/resource |
正式包资源库,编译时会复制到target/classes |
src/test/java |
测试java源代码文件,编译到target/test-classes |
src/test/resource |
测试时资源库,编译时复制到target/test-classes |
建议配置2个logback配置文件:
路径 |
说明 |
src/main/resources/logback.xml |
异步打印到按天轮转的日志文件中。jar包不要配置,避免污染业务配置。 |
src/test/resources/logback-test.xml |
测试时候使用,打印到stdout |
- 线上和开发环境的配置要分离,对于java项目:
- src/main/resources 目录下的东西都是正式环境使用的
- src/test/resources 目录下的东西才是本机开发环境使用的
如果发现自己本机开发启动程序的时候,经常要修改 src/main/resources 目录下的东东,那就说明用错了。
这样做的一个后果就是,当提交代码的时候,忘记修改回来,结果发布到线上去了。轻则日志量暴增,重则引起运营事故。所以一定千万注意!
推荐的配置内容
logback.xml 推荐配置1
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 41 42 43 44 45 46 47 48 49 50 51 52
| <?xml version="1.0" encoding="UTF-8"?> <configuration scan="false" scanPeriod="60 seconds" debug="false"> <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${catalina.home}/logs/fs-app-%d{yyyyMMdd}.log.zip</fileNamePattern> <maxHistory>7</maxHistory> </rollingPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{12} %msg%rEx{full, java.lang.Thread, javassist, sun.reflect, org.springframework, org.apache, org.eclipse.jetty, $Proxy, java.net, java.io, javax.servlet, org.junit, com.mysql, com.sun, org.mybatis.spring, cglib, CGLIB, java.util.concurrent, okhttp, org.jboss, }%n </pattern> </encoder> </appender> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <queueSize>512</queueSize> <appender-ref ref="RollingFile"/> <includeCallerData>true</includeCallerData> </appender> <logger name="druid.sql" level="INFO"/> <logger name="org.hibernate" level="WARN"/> <logger name="org.springframework" level="WARN"/> <logger name="org.apache" level="WARN"/> <root level="info"> <appender-ref ref="ASYNC"/> </root> </configuration>
|
logback.xml 推荐配置2
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 41 42 43
| <?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${catalina.base}/logs/warn.log</File> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>WARN</level> </filter> <encoder> <pattern>[%d{yyyy/MM/dd-HH:mm:ss.SSS}]-[%level]-[%thread]-[%class:%line]- %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${catalina.base}/logs/warn.%d{yyyy-MM-dd}.log.zip</FileNamePattern> <maxHistory>15</maxHistory> </rollingPolicy> </appender>
<appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${catalina.base}/logs/all.log</File> <encoder> <pattern>[%d{yyyy/MM/dd-HH:mm:ss.SSS}]-[%level]-[%thread]-[%class:%line]- %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${catalina.base}/logs/all.%d{yyyy-MM-dd}.log.zip</FileNamePattern> <maxHistory>7</maxHistory> </rollingPolicy> </appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[%d{yyyy/MM/dd-HH:mm:ss.SSS}]-[%level]-[%thread]-[%class:%line]- %msg%n</pattern> </encoder> </appender>
<logger name="com.facishare.open" level="INFO" additivity="false"> <appender-ref ref="WARN"/> <appender-ref ref="ALL"/> </logger>
<root level="info"> <appender-ref ref="WARN"/> <appender-ref ref="ALL"/> </root> </configuration>
|
logback-test.xml 推荐配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0" encoding="UTF-8"?> <configuration scan="false" scanPeriod="60 seconds" debug="false"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{12} %msg%n</pattern> </encoder> </appender> <logger name="org.hibernate" level="WARN"/> <logger name="org.springframework" level="WARN"/> <logger name="org.apache" level="WARN"/> <root level="DEBUG"> <appender-ref ref="STDOUT"/> </root> </configuration>
|
推荐日志级别
极为严格的做法是:只要*log.error()*记录的内容,都需要人及时响应的,有些公司会针对error进行字符串告警。
那么,针对一些如:没有权限、参数错误、非法请求等,由于不合理的请求进来的,就建议打印warn而不是error,否则狼来了喊多了就没有用了。也会淹没真正的错误。
简单来讲,真正影响到正常用户的正常请求而且需要及时响应的错误,就打印ERROR,否则打印WARN。
一般信息打印info,针对调试操作,打印debug。
推荐使用日志占位符
log.info(“this is a={}, b={}”, a, b)
使用占位符,是真正需要打印的时候,才进行字符串拼接;如果不打印就不会拼接字符串。
log.error(“cannot open url={}”, url, e)
针对error,务必把异常栈打印出来,这里有一个exception对象,不需要使用占位符,如果多一个占位符,则只会打印e.getMessage()
的内容,就不方便查问题了。