Logback会按照顺序在5个地方查找相关配置:
- classpath下是否存在logback-test.xml文件,没有继续找;
- classpath下是否存在logback.groovy文件,没有继续找;
- classpath下是否存在logback.xml文件,没有继续找;
- 通过
java.util.ServiceLoader<S>加载com.qos.logback.classic.spi.Configurator的实现,没有继续找; - 采用logback最基本的配置,在 ch.qos.logback.classic.BasicConfigurator,在logback-classic包内可以找到;
正常在项目中都会添加两个配置文件:logback-test.xml[src/test/resources]和logback.xml[src/resources],用于测试和生产环境。
小尝试
新建logback.xml文件,放在/src/resource目录下,内容:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<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默认的配置是一样的哦。
如何实现配置文件自动刷新?
当我们修改了日志配置后,是否可以不重新运行就生效?答案是可以的,而且在生产环境也有可能会调整日志参数,如何实现热加载?
<configuration scan="true" scanPeriod="30 seconds" >
...
</configuration>
scan:添加scan="true"即可实现logback配置文件热加载。
scanPeriod:配置热加载的频率,需要带单位,默认ms。
- 添加scan后,会启动一个定时器:
ReconfigureOnChangeTask,用于检查配置文件; - 如何不添加scanPeriod,默认1m加载一次,配置了但是没有写单位,默认是ms,但生产环境完全没必要这么高的频率
- 吻心提示:为什么你的例子不生效?因为要修改/target目录下的logback.xml才可以,这才是你正在运行的配置,不要去修改src/resource的配置,那是源文件!!!!
如何在日志中记录堆栈跟踪行所在的类和版本信息?
这里对应官网Enabling packaging data in stack traces章节,很多人不明白什么是packing data,先给出一个例子: 首先我们编写一个异常代码:
int i=10;
int j=9/(i-10);
return String.valueOf(j);
不出意外,得到了以下异常:
java.lang.ArithmeticException: / by zero
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.41.jar:9.0.41]
大家看到最后有一个标记:[tomcat-embed-core-9.0.41.jar:9.0.41],这就是packing data,如何才能在日志中打印该内容呢? 在配置中添加packagingData="true"就可以了。
<configuration packagingData="true">
</configuration>
packing data对于识别软件版本问题非常有用。但是,它的计算成本相当高,尤其是在经常抛出异常的应用程序中,慎用!!!
正文开始的地方:Logback的配置文件构成
写在前面
修改contextName
在常用的配置节之前,还有一个配置节<contextName>,用于修改日志记录器的上下文名称(默认default),如果有多个应用程序都在记录日志,使用默认的名称不容易区分,建议把该配置节修改为当前应用程序的名称,如<contextName>idodo-cloud-idp</contextName>。
使用变量property
<!--定义变量-->
<property name="USER_HOME" value="/home/idodo" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!--使用变量-->
<file>${USER_HOME}/cloud-idp.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
有三种方式定义变量(优先级由高到低):
- 使用系统变量,如Java -DUser_HOME="/home/idodo" idodo-cloud-idp
- 在xml中定义变量,如
- 在单独文件中定义变量,如:在idp.properties文件中定义内容USER_HOME=/home/idodo
针对第1、2种方式,在配置文件中直接使用即可,但针对第3种,却有2种使用方式:
- 在配置文件中引入文件
- 如果该文件位于classpath下,可使用resource导入
默认值
在使用变量时,如果变量并不存在,可指定默认值(使用符合:-):${aName:-golden}的默认值是 golden;另外变量和变量的值,都可以引用其他变量,如<property name="USER_${home:-HOME}" value="/home/${app_name:-idodo}" />。
其他快捷方式:使用{HOSTNAME}可以获取主机名。 另外,还可以定义颜色(如define 配置节)或作用域(如scope设置),甚至编写逻辑(如if-then等),基本不常用,感兴趣可以通过官网研究。
第一节、 :配置logger
<logger name="chapters.configuration" level="info" additivity="false">
<!--可以包括 0个 或 多个 -->
<appender-ref></appender-ref>
</logger>
| 属性 | 必须 | 值 | 备注 |
|---|---|---|---|
| name | 必须 | java包或者类名 | 影响package chapters.configuration下的日志行为 |
| level | 可选 | inherited、null、trace, debug, info, warn, error, all或off | 如何设为inherited或null,会默认继承的level属性(下面有介绍) |
| additivity | 可选 | true、false | 是否附加父级的logger,详见:logger的继承关系 |
:配置root logger
<root level="debug">
<!--可以包括 0-n 个 -->
<appender-ref></appender-ref>
</root>
| 属性 | 必须 | 值 | 备注 |
|---|---|---|---|
| level | 必须 | trace, debug, info, warn, error, all或off | 不能设置为inherited和null,没意义 |
只有level属性,因为默认name=root,而且root没有设置additivity的意义。
特别强调:一定要留意《第二节》聊一聊日志系统 Logback#Appender的继承方式,否则会发生日志重复记录的问题
再来一个完整的例子
<configuration>
<contextName>idodo-cloud-idp</contextName>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="idodo.cloud.idp.configuration" level="INFO" />
<logger name="idodo.cloud.idp.configuration.security" level="DEBUG" />
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
第二节、:配置详解
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myApp.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
| 属性 | 必须 | 值 | 备注 |
|---|---|---|---|
| name | 必须 | 字符串 | 用于被其他配置节引用 |
| class | 必须 | ch.qos.logback.core.FileAppender、ConsoleAppender | 输出到哪里的Appender实现类 |
| layout | 可选 | 配置节内容 | 可包含0-n个 |
| encoder | 可选 | 配置节内容 | 可包含0-n个 |
| filter | 可选 | 配置节内容 | 可包含0-n个 |
除了以上属性之外,还可以包含class指定appender类的属性,如FileAppender的文件属性。
Appender 支持哪些 class ?
- ch.qos.logback.core.ConsoleAppender:输出到控制台,主要属性包括target和encoder
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--把 target修改为 System.err,默认是System.out-->
<target>System.err</target>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
- ch.qos.logback.core.FileAppender:输出到文件,主要属性包括append、file和encoder
<configuration>
<!--定义时间片,timeReference表示以日志上下文创建时间为参考-->
<timestamp key="byMin" datePattern="yyyy-MMdd_HHmm" timeReference="contextBirth"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!--日志文件位置,可以是绝对路径或相对路径(运行jar所在为根目录)-->
<!--使用时间片:每次重启项目时都会创建一个新日志文件-->
<file>[${byMin}]_testFile.log</file>
<!--true:表示会在原来日志内容后面追加日志;false:每次重启项目都会清空日志文件-->
<!--无论是否使用时间片作为文件名,只要重启项目时文件名存在就会被清空-->
<append>true</append>
<!-- true:表示立即刷新输出流,保证日志不丢失;false:不会立即刷新,可以提高日志吞吐量 -->
<!--这个属性所有日志类型都有-->
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
- ch.qos.logback.core.rolling.RollingFileAppender:根据策略把日志写到不同的日志文件中(常用),主要属性包括append、file、encoder、rollingPolicy和triggeringPolicy
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
比FileAppender多了两个属性:rollingPolicy和triggeringPolicy
- rollingPolicy:提供了文件移动或重命名等操作策略,负责干什么,详见《《第三节-附录1》介绍RollingFileAppender的使用》
- triggeringPolicy:负责什么时候执行操作,负责时机,详见《《第三节-附录1》介绍RollingFileAppender的使用》
另外,还有很多网络、安全和邮件相关的Appender。
- ch.qos.logback.classic.net.SocketAppender :允许应用程序通过网络连接到远程日志服务器,以便将日志事件发送到服务器
- ch.qos.logback.classic.net.server.ServerSocketAppender:允许客户端通过网络链接到应用程序,以便将日志事件发送到客户端
- ch.qos.logback.classic.net.SMTPAppender:将日志事件累积到一个或多个固定大小的缓冲区中,并在用户指定的事件发生后将适当缓冲区的内容发送到电子邮件中
- ch.qos.logback.classic.db.DBAppender:将日志事件插入到三个数据库表中
- ch.qos.logback.classic.net.SyslogAppender:向远程syslog守护进程发送消息
- ch.qos.logback.classic.sift.SiftingAppender:根据用户会话分离日志事件,以便不同用户生成的日志进入不同的日志文件,每个用户一个日志文件
- ch.qos.logback.classic.AsyncAppender:仅仅充当一个事件分派器,因此必须引用另一个appender才能执行任何有用的操作
Appender 的 encoder 格式
目前PatternLayoutEncoder 是唯一有用的且默认的 ,有一个节点,用来设置日志的输入格式。使用“%”加“转换符”方式配置。
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>