根标签 configuration
属性
<configuration scan="true" scanPeriod="120 seconds" debug="false">
<!-- ... -->
</configuration>
scan
当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod
设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug
当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false
子节点
上下文名称 contextName
默认为default,用于区分不同应用程序的记录,一旦设置,不能修改
使用时可用${contextName}
<configuration scan="true" scanPeriod="120 seconds" debug="false">
<contextName>serverName</contextName>
<!-- ... -->
</configuration>
变量 property
全局变量,类似于maven的pom.xml中的property,有两个属性:name、value,使用时使用${}占位符
<configuration scan="true" scanPeriod="120 seconds" debug="false">
<property name="serverName" value="TestServer"/>
<contextName>${serverName}</contextName>
<!-- ... -->
</configuration>
日志管理 logger
负责写日志 appender
日志管理-logger
可以包含零个或多个
属性
name
用来约束某个包或者某个具体的类
root为全局配置
level
设置日志级别,与大小写无关,默认为DEBUG
日志级别从高到低:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL
- ALL 最低等级的,用于打开所有日志记录。
- TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。
- DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
- INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
- WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
- ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
- FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
- OFF 最高等级的,用于关闭所有日志记录。
additivity
是否向上级logger传递打印信息,默认是true,即INFO级别会向DEBUG传递
例
<configuration>
<!-- 指定包中的日志,日志级别为DEBUG,不向上传递,打印至控制台及指定日志文件 -->
<logger name="test.yong.mapper.dao" additivity="false" level="DEBUG">
<appender-ref ref="console"/>
<appender-ref ref="logfile_info"/>
</logger>
<!-- 指定类中的日志,日志级别为ERROR -->
<logger name="org.mybatis.spring.SqlSessionUtils" level="ERROR"/>
<!-- 配置<appender-ref>使用,设置统一日志级别 -->
<logger name="root" level="INFO">
</logger>
</configuration>
负责写日志-appender
属性
name
appender的名称,全局唯一,appender-ref 关联该name
class
appender的全限定名
ConsoleAppender 日志写到控制台
把日志添加到控制台
<encoder>:对日志进行格式化
<target>:字符串 System.out 或者 System.err ,默认 System.out
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console" />
</root>
</configuration>
FileAppender 日志写到文件
把日志添加到文件
<file>:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
<append>:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
<encoder>:对记录事件进行格式化。
<prudent>:如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。
prudent支持多JVM同时操作同一个日志文件
官方给的说明如下:如果使用prudent模式,FileAppender将安全的写入到指定文件,即使存在运行在不同机器上的、其他JVM中运行的其他FileAppender实例。
Prudent模式更依赖于排他文件锁,经验表明加了文件锁后,写日志的开始是正常的3倍以上。当prudent模式关闭时,每秒logging event的吞吐量为100,000,当prudent模式开启时,大约为每秒33,000
<configuration>
<contextName>serverName</contextName>
<appender name="logfile_info" class="ch.qos.logback.core.FileAppender">
<file>${contextName}.log</file>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="logfile_info" />
</root>
</configuration>
RollingFileAppender 滚动记录文件
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件
<file>:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
<append>:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
<encoder>:对记录事件进行格式化。(具体参数稍后讲解 )
<rollingPolicy>:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。
<triggeringPolicy >: 告知 RollingFileAppender 合适激活滚动。
<prudent>:当为true时,不支持FixedWindowRollingPolicy。支持TimeBasedRollingPolicy,但是有两个限制,1不支持也不允许文件压缩,2不能设置file属性,必须留空。
rollingPolicy 滚动策略
TimeBasedRollingPolicy
最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
<fileNamePattern>:
必要节点,包含文件名及“%d”转换符, “%d”可以包含一个 java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}
RollingFileAppender的file字节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置,当前日志总是记录到file指定的文件(活动文件),
活动文件的名字不会改变;如果没设置file,活动文件的名字会根据fileNamePattern 的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。
<maxHistory>:
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。
假设设置每个月滚动,且 <maxHistory>是6,则只保存最近6个月的文件,删除之前的旧文件。
删除旧文件时,那些为了归档而创建的目录也会被删除。
FixedWindowRollingPolicy
根据固定窗口算法重命名文件的滚动策略
<minIndex>:窗口索引最小值
<maxIndex>:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12。
<fileNamePattern >:
必须包含“%i”例如,假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如,mylog%i.log.gz或者log%i.log.zip
SizeAndTimeBasedRollingPolicy
按时间滚动,按大小归档
必要节点,%d和%i 必须有
<maxFileSize>
最大文件大小,超过大小进行归档
<maxHistory>
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。
<totalSizeCap>
总日志文件最大大小,当总日志文件最大大小超过最大值时,删除旧文件,优先级大于maxHistory
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>
/app/log/${CONTEXT_NAME}/info/${HOSTNAME}.${CONTEXT_NAME}.%d{yyyy-MM-dd}.ysData.%i.log
</FileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
triggeringPolicy 日志触发器策略
SizeBasedTriggeringPolicy: 查看当前活动文件的大小,如果超过指定大小会告知 RollingFileAppender 触发当前活动文件滚动。只有一个节点:
<maxFileSize>:这是活动文件的大小,默认值是10MB。
例:
<!-- 每天生成一个日志文件,保存30天的日志文件 -->
<configuration>
<appender name="loggerFile_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="loggerFile_info" />
</root>
</configuration>
<!-- 按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。 -->
<configuration>
<appender name="loggerFile_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>test.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>tests.%i.log.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>20MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="loggerFile_info" />
</root>
</configuration>
DBAppender 日志入库
DBAppender将日志存入三张表中,这三张表分别为:logging_event, logging_event_property 与 logging_event_exception。在使用 DBAppender 之前,它们必须存在。
logback 自带 SQL 脚本来创建表。这些脚本在 logback-classic/src/main/java/ch/qos/logback/classic/db/script 文件夹下。每一种最流行的数据库都有一个对应的脚本。
目前 logback 支持的数据库方言有 H2, HSQL, MS SQL Server, MySQL, Oracle, PostgreSQL, SQLLite and Sybase。
下面的表格总结了数据库类型,以及它们是否支持 getGeneratedKeys()
方法:
RDBMS | 测试版本 | JDBC 驱动的测试版本 | 是否支持 getGeneratedKeys() | logback 是否提供对应的方言 |
---|---|---|---|---|
DB2 | untested | untested | unknown | NO |
H2 | 1.2.132 | - | unknown | YES |
HSQL | 1.8.0.7 | - | NO | YES |
Microsoft SQL Server | 2005 | 2.0.1008.2 (sqljdbc.jar) | YES | YES |
MySQL | 5.0.22 | 5.0.8 (mysql-connector.jar) | YES | YES |
PostgreSQL | 8.x | 8.4-701.jdbc4 | NO | YES |
Oracle | 10g | 10.2.0.1 (ojdbc14.jar) | YES | YES |
SQLLite | 3.7.4 | - | unknown | YES |
Sybase SQLAnywhere | 10.0.1 | - | unknown | YES |
logging_event 表包含了以下字段:
Field | Type | Description |
---|---|---|
timestamp | big int | 日志事件的创建时间 |
formatted_message | text | 经过 org.slf4j.impl.MessageFormatter 格式化后的消息 |
logger_name | varchar | 发出日志的 logger 名 |
level_string | varchar | 日志事件的级别 |
reference_flag | smallint | 用来表示是否是异常或者与 MDC 属性相关联。它的值通过 ch.qos.logback.classic.db.DBHelper 计算得到。日志时间包含 MDC 或者 Context 时,它的值为 1。包含异常时,它的值为 2。包含两者,则值为 3。 |
caller_filename | varchar | 发出日志请求的文件名 |
caller_class | varchar | 发出日志请求的类 |
caller_method | varchar | 发出日志请求的方法 |
caller_line | char | 发出日志请求所在的行 |
event_id | int | 日志事件在数据库的 id |
logging_event_property 表用于存储 MDC
或者 Context
中的 key 与 value。它包含如下字段:
Field | Type | Description |
---|---|---|
event_id | int | 日志事件的数据库 id |
mapped_key | varchar | MDC 属性的 key |
mapped_value | text | MDC 属性的 value |
logging_event_exception 表包含如下字段:
Field | Type | Description |
---|---|---|
event_id | int | 日志事件的数据库 id |
i | smallint | 堆栈所在的行 |
trace_line | varchar | 相对应的堆栈信息 |
ConnectionSource
ConnectionSource 接口提供了一种可插拔式的方式为需要使用 java.sql.Connection 的 logback 类获取 JDBC 连接。
目前有三种实现,分别为:DataSourceConnectionSource,DriverManagerConnectionSource 与 JNDIConnectionSource
DriverManagerConnectionSource
DriverManagerConnectionSource 实现了 ConnectionSource 接口,通过基于 URL 的传统 JDBC 方式来获取连接。
这个类为每一个调用 getConnection()
的方法都新建一个 Connection
连接。推荐你使用本地支持的连接池的 JDBC 驱动,或者创建你自己实现的 ConnectionSource
,基于你已经使用的任何连接池机制
<!-- DriverManagerConnectionSource示例 -->
<configuration>
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://host_name:3306/datebase_name</url>
<user>username</user>
<password>password</password>
</connectionSource>
</appender>
<root level="DEBUG" >
<appender-ref ref="DB" />
</root>
</configuration>
JNDIConnectionSource
JNDIConnectionSource是 logback 自带的,ConnectionSource的另一种实现。从名字可以看出来,它通过 JNDI 获取 javax.sql.DataSource,然后再获取 java.sql.Connection 实例。JNDIConnectionSource主要设计用在 J2EE 应用服务器以及应用服务器客户端中,这里假设应用服务器支持远程获取 javax.sql.DataSource。因为可以利用连接池或者其它应用服务器所提供的好处。更加重要的是,你的应用不需要做重复的工作,因为不需要在 logback.xml 中定义一个 DataSource。
<!-- tomcat中配置jndl -->
<Context docBase="/path/to/app.war" path="/myapp">
...
<Resource name="jdbc/logging"
auth="Container"
type="javax.sql.DataSource"
username="..."
password="..."
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost/..."
maxActive="8"
maxIdle="4"/>
...
</Context>
<!-- JNDIConnectionSource示例 -->
<configuration debug="true">
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.JNDIConnectionSource">
<!-- please note the "java:comp/env/" prefix -->
<jndiLocation>java:comp/env/jdbc/logging</jndiLocation>
</connectionSource>
</appender>
<root level="INFO">
<appender-ref ref="DB" />
</root>
</configuration>
这个类通过无参构造函数获取一个 javax.naming.InitialContext
。在 J2EE 环境通常可以行得通。但是在 J2EE 环境之外,你需要根据 JNDI 提供者的文档提供一个 jndi.properties 属性文件
DataSourceConnectionSource
<configuration debug="true">
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="${dataSourceClass}">
<!-- Joran 不能替换不是属性的变量。因此我们不能像其它变量一样声明接下来的变量
-->
<param name="${url-key:-url}" value="${url_value}"/>
<serverName>${serverName}</serverName>
<databaseName>${databaseName}</databaseName>
</dataSource>
<user>${user}</user>
<password>${password}</password>
</connectionSource>
</appender>
<root level="INFO">
<appender-ref ref="DB" />
</root>
</configuration>
在这个例子中,我们大量使用了变量替换。当需要把一些连接的细节集中在一个配置文件中,并且通过 logback 与其它框架共享时非常方便。
连接池
日志事件可以很快的被创建。为了让日志事件都能被插入到数据库,推荐DBAppender使用连接池配置。
经过实验发现,使用连接池,可以让 DBAppender 有大幅的性能提升。下面的配置文件,将日志事件发送给 MySQL,没有使用连接池。
<configuration>
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
<serverName>${serverName}</serverName>
<port>${port$</port>
<databaseName>${dbName}</databaseName>
<user>${user}</user>
<password>${pass}</password>
</dataSource>
</connectionSource>
</appender>
<root level="DEBUG">
<appender-ref ref="DB" />
</root>
</configuration>
在这个配置文件中,发送 500 个日志事件到 MySQL 数据库,需要高达 5 秒的时间,相当每条请求需要 10 毫秒。在大型的应用中,这个数字是不能够被接受的。
DBAppender` 连接池需要使用一个专业的外部库。下一个例子中使用 c3p0。为了使用 c2p0,你需要下载并将 c3p0-VERSION.jar 放在类路径下。
<configuration>
<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
<connectionSource
class="ch.qos.logback.core.db.DataSourceConnectionSource">
<dataSource
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<jdbcUrl>jdbc:mysql://${serverName}:${port}/${dbName}</jdbcUrl>
<user>${user}</user>
<password>${password}</password>
</dataSource>
</connectionSource>
</appender>
<root level="DEBUG">
<appender-ref ref="DB" />
</root>
</configuration>
使用这个新的配置,发送 500 条日志事件到 MySQL 数据库大约需要 0.5 秒,大约 1 毫秒一条请求,性能提升了十倍。
SiftingAppender 分离或者过滤日志
SiftingAppender 根据给定的运行时属性分离或者过滤日志。例如,SiftingAppender 可以根据用户的 session 分离日志,因此不同的用户的日志会有不同的日志文件,一个用户一个日志文件。
属性名 | 类型 | 描述 |
---|---|---|
timeout | Duration | 一个内置的 appender 如果在指定 timeout 时间内没有被访问,则被认为是过时的。一个过时的 appender 会被关闭,并且不会被 SiftingAppende 所引用。默认值为 30 分钟 |
maxAppenderCount | integer | SiftingAppender 可以创建并且跟踪内置 appender 的最大数量。默认值为 Integer.MAX_VALUE |
通过动态创建来实现这个。SiftingAppender 通过配置文件中指定的模板 (通过闭合的 <sift> 元素,见下面的例子) 来创建内置的 appender。SiftingAppender 负责管理子 appender 的生命周期。例如,SiftingAppender 会自动关闭并移除任何过时的 appender。在指定的 timeout 时间内没有被访问过的内置 appender,被认为是过时的。
在处理一个日志事件时,SiftingAppender会委托一个子 appender 去进行处理。选择的标准是通过 discriminator 在运行时计算。用户也可以通过 Discriminator 来指定一个选择标准。
示例
应用通过打印日志来表明应用已经启动。通过 MDC 设置键 “userid” 对应的值为 “Alice”,并打印了一条日志信息。
logger.debug("Application started");
MDC.put("userid", "Alice");
logger.debug("Alice says hello");
<configuration>
<property name="FILE_NAME" value="FILE" />
<appender name="SIFT"
class="ch.qos.logback.classic.sift.SiftingAppender">
<!-- 在缺少 class 属性的情况下,默认的 discriminator 类型为 ch.qos.logback.classic.sift.MDCBasedDiscriminator -->
<discriminator>
<key>userid</key>
<defaultValue>unknown</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${userid}"
class="ch.qos.logback.core.FileAppender">
<file>${userid}_${FILE_NAME}.log</file>
<append>false</append>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</pattern>
</layout>
</appender>
</sift>
</appender>
<root level="DEBUG">
<appender-ref ref="SIFT" />
</root>
</configuration>
在没有 class 属性的情况下,默认的 discriminator 类型为 MDCBasedDiscriminator。discriminator 的的值为 MDC 的 key 所对应的值。但是,如果 MDC 的值为 null,那么 defaultValue 的将为 discriminator 的值。
SiftingAppender 的独特之处在于它有能力去引用以及配置子 appender。在上面的例子中,SiftingAppender 会创建多个 FileAppender 实例。每个 FileAppender 实例通过 MDC 的 key 所对应的值来标识。每当 MDC 的 key “userid” 被分配一个新值时,一个新的 FileAppender 将会被构建。SiftingAppender 可以追踪它所创建的 appender。appender 在 30 分钟之内没有被使用将会被自动关闭并丢弃。
导出变量 有不同 appender 实例是不够的。每一个实例都必须输出到一个唯一的资源中。为了做到这种区分,在 appender 模板中,key 被传递给 discriminator。在上面的例子中是 “userid”,它将被导出并变成一个变量。因此,该变量可以通过给定的子 appender 来区分具体的资源。
在上面的示例中,使用 “byUserid.xml” 来运行 SiftExample,将会创建两个不同的日志文件,“unknown.log” 与 “Alice.log”。
本地变量 在版本 1.0.12 中,配置文件中局部变量的属性也可以应用到内置的 appender 中。而且,你可以在 元素中定义变量以及动态定义属性。或者在 元素之外定义变量,在里面使用也是支持的。
获取正确的 timeout
对于特定类型的应用,正确的获取 timeout 参数非常困难。如果 timeout 过小,一个新的内置 appender 在创建几秒钟之后就被移除了。这种现象被称为 “制造垃圾”。如果 timeout 的值过大,那么 appender 会快速接连的被创建,可能会耗尽资源。同理,设置 maxAppenderCount 的值太低会产生垃圾。
在大多数情况下,在代码中显示的指出不需要再创建内置的 appender。需要在代码中标记日志事件为 FINALIZE_SESSION。无论什么时候 SiftingAppender 看到日志事件标记为 FINALIZE_SESSION,它将会终结相关的子 appender。在生命周期快结束时,内置的 appender 将会留存几秒钟来处理之后到来的日志事件,然后再关闭。
import org.slf4j.Logger;
import static ch.qos.logback.classic.ClassicConstants.FINALIZE_SESSION_MARKER;
void job(String jobId) {
MDC.put("jobId", jobId);
logger.info("Starting job.");
... do whather the job needs to do
// 将导致内置 appender 结束生命周期。但是会留存几秒钟
logger.info(FINALIZE_SESSION_MARKER, "About to end the job");
try {
.. perform clean up
} catch(Exception e);
// 被留存的 appender 处理,但是不会再创建新的 appender
logger.error("unexpected error while cleaning up", e);
}
}
其余appender
SocketAppender、SMTPAppender、SyslogAppender、SiftingAppender
<encoder>
负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。
目前PatternLayoutEncoder 是唯一有用的且默认的encoder ,有一个<pattern>节点,用来设置日志的输入格式。使用“%”加“转换符”方式,如果要输出“%”,则必须用“\”对“%”进行转义
例:
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
转换符 作用
c {length } lo {length } logger {length } | 输出日志的logger名,可有一个整形参数,功能是缩短logger名,设置为0表示只输入logger最右边点符号之后的字符串。 Conversion specifier Logger name Result%loggermainPackage.sub.sample.BarmainPackage.sub.sample.Bar%logger{0}mainPackage.sub.sample.BarBar%logger{5}mainPackage.sub.sample.Barm.s.s.Bar%logger{10}mainPackage.sub.sample.Barm.s.s.Bar%logger{15}mainPackage.sub.sample.Barm.s.sample.Bar%logger{16}mainPackage.sub.sample.Barm.sub.sample.Bar%logger{26}mainPackage.sub.sample.BarmainPackage.sub.sample.Bar |
C {length } class {length } | 输出执行记录请求的调用者的全限定名。参数与上面的一样。尽量避免使用,除非执行速度不造成任何问题。 |
contextName cn | 输出上下文名称。 |
d {pattern } date {pattern } | 输出日志的打印日志,模式语法与java.text.SimpleDateFormat 兼容。 Conversion Pattern Result%d2006-10-20 14:06:49,812%date2006-10-20 14:06:49,812%date{ISO8601}2006-10-20 14:06:49,812%date{HH:mm:ss.SSS}14:06:49.812%date{dd MMM yyyy ;HH:mm:ss.SSS}20 oct. 2006;14:06:49.812 |
F / file | 输出执行记录请求的java源文件名。尽量避免使用,除非执行速度不造成任何问题。 |
caller{depth} caller{depth, evaluator-1, … evaluator-n} | 输出生成日志的调用者的位置信息,整数选项表示输出信息深度。例如, %caller{2} 输出为:0 [main] DEBUG - logging statement Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22) Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17) 例如, %caller{3} 输出为: 16 [main] DEBUG - logging statement Caller+0 at mainPackage.sub.sample.Bar.sampleMethodName(Bar.java:22) Caller+1 at mainPackage.sub.sample.Bar.createLoggingRequest(Bar.java:17) Caller+2 at mainPackage.ConfigTester.main(ConfigTester.java:38) |
L / line | 输出执行日志请求的行号。尽量避免使用,除非执行速度不造成任何问题。 |
m / msg / message | 输出应用程序提供的信息。 |
M / method | 输出执行日志请求的方法名。尽量避免使用,除非执行速度不造成任何问题。 |
n | 输出平台先关的分行符“\n”或者“\r\n”。 |
p / le / level | 输出日志级别。 |
r / relative | 输出从程序启动到创建日志记录的时间,单位是毫秒 |
t / thread | 输出产生日志的线程名。 |
replace(p ){r, t} | p 为日志内容,r 是正则表达式,将p 中符合r 的内容替换为t 。例如, “%replace(%msg){‘\s’, ‘’}” |
格式修饰符,与转换符共同使用:
可选的格式修饰符位于“%”和转换符之间。
第一个可选修饰符是左对齐 标志,符号是减号“-”;接着是可选的最小宽度 修饰符,用十进制数表示。
如果字符小于最小宽度,则左填充或右填充,默认是左填充(即右对齐),填充符为空格。
如果字符大于最小宽度,字符永远不会被截断。最大宽度 修饰符,符号是点号"."后面加十进制数。
如果字符大于最大宽度,则从前面截断。点符号“.”后面加减号“-”在加数字,表示从尾部截断。
例如:%-4relative 表示,将输出从程序启动到创建日志记录的时间 进行左对齐 且最小宽度为
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}| %-4relative [%thread][%-5level][%logger:%L]%n %msg%n</pattern>
<charset>GBK</charset>
</encoder>
<filter>
过滤器,执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一。
- DENY,日志将立即被抛弃不再经过其他过滤器;
- NEUTRAL,有序列表里的下个过滤器过接着处理日志;
- ACCEPT,日志会被立即处理,不再经过剩余过滤器。
过滤器被添加到<Appender>中,为<Appender>添加一个或多个过滤器后,可以用任意条件对日志进行过滤。<Appender> 有多个过滤器时,按照配置顺序执行。
LevelFilter
级别过滤器,根据日志级别进行过滤
如果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志
<level>:设置过滤级别
<onMatch>:用于配置符合过滤条件的操作
<onMismatch>:用于配置不符合过滤条件的操作
<!-- 将过滤器的日志级别配置为INFO,所有INFO级别的日志交给appender处理,非INFO级别的日志,被过滤掉 -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger{30} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
ThresholdFilter
临界值过滤器,过滤掉低于指定临界值的日志
当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝
<!-- 过滤掉所有低于INFO级别的日志 -->
<configuration>
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<!-- 过滤掉 TRACE 和 DEBUG 级别的日志-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger{30} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
EvaluatorFilter
求值过滤器,评估、鉴别日志是否符合指定条件
需要额外的两个JAR包,commons-compiler.jar和janino.jar
<evaluator>
鉴别器,常用的鉴别器是JaninoEventEvaluato,也是默认的鉴别器,它以任意的java布尔值表达式作为求值条件,求值条件在配置文件解释过成功被动态编译,布尔值表达式返回true就表示符合过滤条件。evaluator有个子标签<expression>,用于配置求值条件
求值表达式作用于当前日志,logback向求值表达式暴露日志的各种字段:
Name | Type | Description |
---|---|---|
event | LoggingEvent | 与记录请求相关联的原始记录事件,下面所有变量都来自event,例如,event.getMessage()返回下面"message"相同的字符串 |
message | String | 日志的原始消息,例如,设有logger mylogger,“name"的值是"AUB”,对于 mylogger.info(“Hello {}”,name); "Hello {}"就是原始消息。 |
formatedMessage | String | 日志被各式话的消息,例如,设有logger mylogger,“name"的值是"AUB”,对于 mylogger.info(“Hello {}”,name); "Hello Aub"就是格式化后的消息。 |
logger | String | logger 名。 |
loggerContext | [LoggerContextVO](https://www.iteye.com/admin/blogs/xref/ch/qos/logback/classic/spi/LoggerContextVO.html) | 日志所属的logger上下文。 |
level | int | 级别对应的整数值,所以 level > INFO 是正确的表达式。 |
timeStamp | long | 创建日志的时间戳。 |
marker | Marker | 与日志请求相关联的Marker对象,注意“Marker”有可能为null,所以你要确保它不能是null。 |
mdc | Map | 包含创建日志期间的MDC所有值得map。访问方法是: mdc.get(“myKey”) 。mdc.get()返回的是Object不是String,要想调用String的方法就要强转,例如,((String) mdc.get("k")).contains("val") .MDC可能为null,调用时注意。 |
throwable | java.lang.Throwable | 如果没有异常与日志关联"throwable" 变量为 null. 不幸的是, “throwable” 不能被序列化。在远程系统上永远为null,对于与位置无关的表达式请使用下面的变量throwableProxy |
throwableProxy | [IThrowableProxy](https://www.iteye.com/admin/blogs/xref/ch/qos/logback/classic/spi/IThrowableProxy.html) | 与日志事件关联的异常代理。如果没有异常与日志事件关联,则变量"throwableProxy" 为 null. 当异常被关联到日志事件时,“throwableProxy” 在远程系统上不会为null |
<onMatch>:用于配置符合过滤条件的操作
<onMismatch>:用于配置不符合过滤条件的操作
<!-- 过滤掉所有日志消息中不包含“billing”字符串的日志 -->
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return message.contains("billing");</expression>
</evaluator>
<OnMatch>ACCEPT </OnMatch>
<OnMismatch>DENY</OnMismatch>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console" />
</root>
</configuration>
<matcher>
匹配器
尽管可以使用String类的matches()方法进行模式匹配,但会导致每次调用过滤器时都会创建一个新的Pattern对象,为了消除这种开销,可以预定义一个或多个matcher对象,定以后就可以在求值表达式中重复引用。
<matcher>是<evaluator>的子标签。
<matcher>中包含两个子标签,一个是<name>,用于定义matcher的名字,求值表达式中使用这个名字来引用matcher;另一个是<regex>,用于配置匹配条件
<configuration debug="true">
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<matcher>
<Name>odd</Name>
<!-- filter out odd numbered statements -->
<regex>statement [13579]</regex>
</matcher>
<expression>odd.matches(formattedMessage)</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="console" />
</root>
</configuration>
MDC使用
logback.xml中配置:
使用%X{xxx} 进行占位,可配置多个,名称不能重复
<!-- %X{logToken}为MDC的占位符 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%X{logToken}|%X{IP}|%X{HOSTNAME}| %-4relative [%thread][%-5level][%logger:%L]%n %msg%n</pattern>
<charset>GBK</charset>
</encoder>
在java代码中赋值,可put多个与占位符名称相同的属性,无顺序要求
MDC.put("logToken", "xxxxxx");
MDC.put("IP",getServerIpAddress());
MDC.put("HOSTNAME",getHostName());
MDC线程安全,使用结束后应及时清除MDC
// 清空全部
MDC.clear();
// 移除指定key
MDC.remove(key);
导入其他logback文件
<!-- logback.xml -->
<configuration>
<contextName>xxxx</contextName>
<!-- <include resource="org/springframework/boot/logging/logback/base.xml"/> -->
<include resource="logback-common.xml"/>
</configuration>
<?xml version="1.0" encoding="GBK"?>
<!-- logback-common.xml -->
<included>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread][track: %X{trackToken}] %-5level %logger:%L%n
%msg%n
</pattern>
<charset>GBK</charset>
</encoder>
</appender>
<appender name="logfile_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<Prudent>true</Prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>
/app/log/${CONTEXT_NAME}/error/${HOSTNAME}.${CONTEXT_NAME}.%d{yyyy-MM-dd-HH}.error.log
</FileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread][%X{trackToken}][%-5level][%logger:%L]%n %msg%n
</pattern>
<charset>GBK</charset>
</encoder>
</appender>
<appender name="logfile_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<!--<onMatch>ACCEPT</onMatch>-->
<!--<onMismatch>DENY</onMismatch>-->
</filter>
<Prudent>true</Prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>
/app/log/${CONTEXT_NAME}/debug/${HOSTNAME}.${CONTEXT_NAME}.%d{yyyy-MM-dd-HH}.debug.log
</FileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4relative [%thread][%X{trackToken}][%-5level][%logger:%L]%n %msg%n
</pattern>
<charset>GBK</charset>
</encoder>
</appender>
<logger name="root" level="DEBUG">
<appender-ref ref="logfile_debug"/>
<appender-ref ref="logfile_error"/>
</logger>
<logger name="xxxx" level="DEBUG"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>
<logger name="org.apache.camel" level="ERROR"/>
<logger name="org.apache.activemq.transport" level="WARN"/>
<logger name="java.sql" level="DEBUG"/>
<logger name="com.mchange" level="WARN"/>
<logger name="org.springframework" level="WARN"/>
<logger name="org.apache.commons" level="WARN"/>
<logger name="org.apache.http.wire" level="OFF"/>
<logger name="org.apache.http.headers" level="OFF"/>
<logger name="org.springframework.data.mongodb.core" level="DEBUG"/>
<logger name="org.mongodb.driver.cluster" level="WARN"/>
<logger name="org.mongodb.driver.protocol.command" level="WARN"/>
<logger name="com.netflix" level="INFO"/>
<logger name="org.apache.http.impl.conn" level="INFO"/>
<logger name="org.apache.http.client.protocol" level="INFO"/>
</included>
与SpringBoot结合
官方推荐使用logback-spring.xml作为配置文件命名
<springProfile>
<springProfile> 标签允许我们更加灵活配置文件,可选地包含或排除配置部分。
元素中的任何位置均支持轮廓部分。使用该name属性指定哪个配置文件接受配置。可以使用逗号分隔列表指定多个配置文件。
<springProfile name="dev">
<!-- 开发环境时激活 -->
</springProfile>
<springProfile name="dev,test">
<!-- 开发,测试的时候激活-->
</springProfile>
<springProfile name="!prod">
<!-- 当 "生产" 环境时,该配置不激活-->
</springProfile>
<!-- 开发环境日志级别为DEBUG -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<!-- 测试环境日志级别为INFO -->
<springProfile name="test">
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<springProperty>
1.该 <springProperty> 标签允许我们从Spring中显示属性,Environment 以便在Logback中使用。如果你想将 application.properties在回读配置中访问文件中的值,这将非常有用
2.标签的工作方式与Logback的标准 <property> 标签类似,但不是直接value 指定source属性(从Environment)指定。
scope 如果需要将属性存储在local范围之外的其他位置,则可以使用该属性。如果您需要一个后备值,以防该属性未设置,则Environment可以使用该defaultValue属性。
<!-- 读取spring.application.name中的属性来生成日志文件名 -->
<!-- 如果无法获取,在springProperty前添加property标签 -->
<springProperty scope="context" name="logName" source="spring.application.name" defaultValue="localhost.log"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/${logName}.log</file> <!-- 使用方法 -->
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/${logName}-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] %mdc{client} %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
</filter>
</appender>