Logback 日志框架详解
Logback 是一个日志框架,旨在成为 log4j 的替代品。它由 Ceki Gülcü 创建并维护,是一款开源的日志框架,是 slf4j(Simple Logging Facade for Java)的实现。相比于 log4j,Logback 具有更高的性能和更好的可扩展性,并提供了众多的特性,如异步日志、动态日志级别、决策器等。在项目中使用 Logback 可以很方便地记录系统运行时的信息、
一、Logback 简介
Logback 是一个日志框架,旨在成为 log4j 的替代品。它由 Ceki Gülcü 创建并维护,是一款开源的日志框架,是 slf4j(Simple Logging Facade for Java)的实现。相比于 log4j,Logback 具有更高的性能和更好的可扩展性,并提供了众多的特性,如异步日志、动态日志级别、决策器等。
在项目中使用 Logback 可以很方便地记录系统运行时的信息、警告和错误等,对于开发人员来说是非常有帮助的。
Logback 的基本概念。
- Logger:Logger 是 Logback 的核心概念,它用于记录日志。Logger 是按照类的层次结构进行命名的,每个 Logger 对象都有一个名字,如果没有显式指定名字,则使用当前类的全限定名作为它的名字。
- Appender:Appender 用于定义日志的输出方式,例如输出到控制台、写入文件、发送邮件等。Logback 有多种类型的 Appender,可以同时输出到多个目标。
- Layout:Layout 用于定义日志输出格式,例如日期格式、日志级别、线程名、类名等。Logback 有多种类型的 Layout,可以根据需求选择使用。
- Filter:Filter 用于对日志进行过滤,可以根据日志级别、关键字、线程名等条件进行过滤。
二、Logback 的主要功能和特点
1. Logback 的主要功能
Logback 的主要功能包括:
- 支持多种日志级别:Logback 支持多种日志级别,包括 TRACE、DEBUG、INFO、WARN 和 ERROR 等。
- 多种日志输出方式:Logback 支持将日志输出到控制台、文件、Syslog、JMS、邮件等多种输出方式,用户可以根据自己的需求选择不同的 Appender。
- 灵活的配置方式:Logback 的配置文件可以使用 XML 或者 Groovy 编写,非常灵活方便。
- 高性能:Logback 的性能非常好,可以满足高并发场景下的需求。
- 精细的过滤功能:Logback 支持使用 Filter 对日志进行精细的过滤操作,可以根据日志级别、线程名、关键字等条件进行过滤。
2. Logback 的特点
Logback 与其他日志系统相比,具有以下几个特点:
- 高性能:Logback 是目前 Java 日志框架中性能最好的一个,它支持异步输出和无锁数据结构等方式来提升性能。
- 灵活的配置:Logback 配置文件可以使用 XML 或者 Groovy 编写,非常灵活方便。同时,Logback 还提供了 Web 界面工具 JaninoConfigurer,可以通过 Web 页面来配置 Logback。
- 多种输出方式:Logback 支持多种输出方式,并且可以自定义 Appender 和 Layout,对于比较复杂的应用场景也可以很好地满足需求。
- 易于集成:对于 Spring、Hibernate、Lucene 等流行框架,Logback 都提供了官方的集成插件,使用起来非常方便。
三、Logback 常用配置
1. name 属性
Logger 中的 name 属性用于记录器的命名,它是一个字符串,可以用任何字符串来命名 Logger。Logback 中同一个 Logger 可以有多个子 Logger,它们之间构成了一个层次结构,其命名规则按照“类所在包名+类名称”的方式进行。例如:
<logger name="com.demo.UserService" level="DEBUG" additivity="false">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</logger>
上述配置中,Logger 的 name 属性为 com.demo.UserService,表示一个 UserService 类的 Logger。如果不指定 name,则默认使用 RootLogger,即根 Logger。
2. level 属性
Logger 的 level 属性用于指定输出的日志级别,Logback 日志的级别由低到高分别为 TRACE、DEBUG、INFO、WARN、ERROR、OFF。若设置了 Logger 的 level 属性,则将只输出指定级别及更高级别的日志信息,例如:
<logger name="com.demo.UserService" level="DEBUG" additivity="false">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</logger>
上述配置中,Logger 的 level 属性为 DEBUG,表示只输出 DEBUG 级别及更高级别的日志信息。
3. additivity 属性
additivity 属性表示是否继承父 Logger 的 Appender,即是否在父 Logger 的 Appender 中同时输出相同的日志信息。如果为 false,则该 Logger 只会将日志信息输出到自己指定的 Appender 中,并不会将日志信息传递给父 Logger。默认情况下,additivity 属性为 true。
<logger name="com.demo.UserService" level="DEBUG" additivity="false">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</logger>
上述配置中,additivity 属性为 false,表示 UserService Logger 只会将日志信息输出到自己指定的 Appender,而不会将日志信息传递给 RootLogger(父 Logger)。
4. ConsoleAppender 配置
ConsoleAppender 可以将日志信息输出到控制台,配置示例如下:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
上述配置中,我们定义了一个名为 CONSOLE 的 Appender,其 class 属性指定为 ch.qos.logback.core.ConsoleAppender,表示输出到控制台。具体细节如下:
(1)target:指定输出目标,可以是 System.out 或 System.err,默认为 System.out。
(2)encoder:指定输出格式,通常使用 PatternLayoutEncoder 来指定输出格式,具体内容详见 Layout 配置。
5. FileAppender 配置
FileAppender 可以将日志信息输出到文件中,配置示例如下:
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>log/test.log</file>
<append>false</append>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n</pattern>
</encoder>
</appender>
上述配置中,我们定义了一个名为 FILE 的 Appender,其 class 属性指定为 ch.qos.logback.core.FileAppender,表示输出到文件。具体细节如下:
(1)file:指定输出文件路径及名称。
(2)append:指定是否追加数据到输出文件中,若为 true 则追加,否则覆盖,默认值为 true。
(3)encoder:指定输出格式,通常使用 PatternLayoutEncoder 来指定输出格式,具体内容详见 Layout 配置。
6. RollingFileAppender 配置
RollingFileAppender 可以将日志信息输出到文件中,同时支持按时间、大小等条件进行切割,以避免单个日志文件过大的问题,配置示例如下:
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>log/test.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>log/test.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n</pattern>
</encoder>
</appender>
上述配置中,我们定义了一个名为 ROLLING_FILE 的 Appender,其 class 属性指定为 ch.qos.logback.core.rolling.RollingFileAppender,表示输出到文件。具体细节如下:
(1)file:指定输出文件路径及名称。
(2)rollingPolicy:指定切割策略,此处使用的是 ch.qos.logback.core.rolling.TimeBasedRollingPolicy,表示按时间切割。fileNamePattern 即指定切割后文件名称的格式,maxHistory 指定最大的历史文件个数。
(3)encoder:指定输出格式,通常使用 PatternLayoutEncoder 来指定输出格式,具体内容详见 Layout 配置。
7. SMTPAppender 配置
SMTPAppender 可以将日志信息以邮件形式发送到指定邮箱,配置示例如下:
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>smtp.test.com</smtpHost>
<smtpPort>465</smtpPort>
<ssl>true</ssl>
<username>test@test.com</username>
<password>123456</password>
<to>test1@test.com,test2@test.com</to>
<from>test@test.com</from>
<subject>错误日志</subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout"/>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
</appender>
上述配置中,我们定义了一个名为 EMAIL 的 Appender,其 class 属性指定为 ch.qos.logback.classic.net.SMTPAppender,表示通过邮件发送日志信息。具体细节如下:
(1)smtpHost、smtpPort:指定邮件服务器的地址和端口。
(2)ssl:是否使用 SSL 连接邮件服务器。
(3)username、password:邮件服务器的登录账号和密码。
(4)to、from:指定接收邮件的邮箱地址和发送者邮箱地址。
(5)subject:邮件主题。
(6)layout:指定输出格式,可以使用各种 Layout 类型,此处使用的是 HTMLLayout。
(7)filter:指定过滤条件,此处使用的是 ThresholdFilter,表示只发送 ERROR 级别及以上的日志信息。
8. PatternLayout 配置
PatternLayout 可以按照指定的格式输出日志信息,下面是一些常用的格式占位符及其含义:
(1)%d{HH:mm:ss.SSS}:输出日志的时间,精确到毫秒。
(2)[%thread]:输出日志的线程名。
(3)%-5level:输出日志级别,左对齐并占位 5 个字符,若不足则用空格补齐。
(4)%logger{36}:输出日志所在类的名称,最长 36 个字符。
(5): %msg%n:输出日志消息及换行符。
配置示例如下:
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} : %msg%n</pattern>
</encoder>
上述配置中,我们使用 PatternLayoutEncoder 来指定输出格式,其 pattern 属性指定了输出格式。具体细节可见上面的格式占位符及其含义。
9. HTMLLayout 配置
HTMLLayout 可以将日志信息以 HTML 格式进行输出,用于可视化展示和查看。配置示例如下:
<layout class="ch.qos.logback.classic.html.HTMLLayout"/>
上述配置中,我们使用 HTMLLayout 类型来指定输出格式,其 class 属性指定为 ch.qos.logback.classic.html.HTMLLayout。如果需要添加样式和自定义输出内容,可以通过 CSS 和 Header、Footer 配置进行实现。
10. LevelFilter 配置
LevelFilter 用于根据日志级别过滤日志信息,可用于只记录某些级别的日志信息或忽略某些级别的日志信息,配置示例如下:
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
上述配置中,我们使用 LevelFilter 类型来指定过滤器,其 class 属性指定为 ch.qos.logback.classic.filter.LevelFilter。具体细节如下:
(1)level:指定要过滤的日志级别。
(2)onMatch:指定当过滤条件匹配时要执行的操作,此处使用 DENY 表示拒绝输出。
(3)onMismatch:指定当过滤条件未匹配时要执行的操作,此处使用 ACCEPT 表示接受输出。
- DuplicateMessageFilter 配置
DuplicateMessageFilter 用于过滤掉重复的日志信息,即当多个日志消息内容相同时,只记录其中一个日志信息,可用于减少日志量或避免误导信息,配置示例如下:
<filter class="ch.qos.logback.classic.filter.DuplicateMessageFilter">
<allowedRepetitions>1</allowedRepetitions>
</filter>
上述配置中,我们使用 DuplicateMessageFilter 类型来指定过滤器,其 class 属性指定为 ch.qos.logback.classic.filter.DuplicateMessageFilter。allowedRepetitions 属性指定了允许的重复次数,此处设置为 1 表示当某个日志消息出现重复内容时,只记录一次该日志信息。
四、配置示例
1. 一个简单常用的配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义日志文件保存的路径和文件名 -->
<property name="LOG_HOME" value="/var/log/myapp"/>
<property name="APP_NAME" value="myapp"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按日期拆分的文件输出 -->
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 过滤一些无用的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!-- 设置日志记录器 -->
<logger name="com.mypackage" level="debug" additivity="false">
<appender-ref ref="rollingFile"/>
<appender-ref ref="console"/>
</logger>
<!-- 根的日志记录器 -->
<root level="error">
<appender-ref ref="rollingFile"/>
<appender-ref ref="console"/>
</root>
</configuration>
上述配置代码中,控制台输出和按日期拆分的文件输出是两个常见的 appender。这里也可以添加其他的 appender 来实现将日志发往不同渠道(邮件、数据库等),根据需要进行修改即可。在日志文件备份方面,这里使用了 TimeBasedRollingPolicy 滚动策略,可以在每天或每个小时结束时生成一个新的日志文件。当然,也可以使用 SizeAndTimeBasedRollingPolicy 等其他的日志文件备份策略。
注意,上述代码中的路径、文件名、包名等都是示例,实际应用时需要根据具体情况进行修改。
2. ELK相关配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} : %msg%n</pattern>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} : %msg%n</pattern>
</encoder>
</appender>
<appender name="logstash" class="ch.qos.logback.core.net.SyslogAppender">
<syslogHost>${ELK_HOST}</syslogHost>
<syslogPort>${ELK_PORT}</syslogPort>
<suffixPattern>%msg%n</suffixPattern>
<facility>USER</facility>
<includeMDC>true</includeMDC>
<layout class="net.logstash.logback.layout.LogstashLayout">
<jsonFormatter class="net.logstash.logback.jackson.LogstashJacksonJsonProvider"/>
<fieldNames>
<message>log</message>
</fieldNames>
<customFields>{"app_name":"${appName}"}</customFields>
</layout>
</appender>
<logger name="com.example" level="INFO">
<appender-ref ref="logstash"/>
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</logger>
<root level="INFO">
<appender-ref ref="logstash"/>
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>
3. 比较详细的配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 定义日志文件保存的路径和文件名 -->
<property name="LOG_DIR" value="/var/log/myapp"/>
<property name="APP_NAME" value="myapp"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按日期拆分的文件输出 -->
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!-- 异步输出日志,避免阻塞主线程 -->
<appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<appender-ref ref="rollingFile"/>
<!-- 还可以添加其他 appender -->
</appender>
<!-- 按大小和日期拆分的文件输出,比较灵活 -->
<appender name="rollingFile2" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!-- 根据系统环境变量动态配置日志级别 -->
<appender name="dynamicThresholdLogging" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator>
<key>env</key>
<defaultValue>dev</defaultValue>
</discriminator>
<sift>
<appender name="FILE-${env}" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${APP_NAME}-${env}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${APP_NAME}-${env}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${env == 'prod' ? 'INFO' : 'DEBUG'}</level>
</filter>
</appender>
</sift>
</appender>
<!-- 设置日志记录器 -->
<logger name="com.mypackage" level="debug" additivity="false">
<appender-ref ref="asyncAppender"/>
</logger>
<!-- 根的日志记录器 -->
<root level="error">
<appender-ref ref="asyncAppender"/>
<appender-ref ref="console"/>
</root>
<!-- MDC(Mapped Diagnostic Context) -->
<conversionRule conversionWord="reqId" converterClass="com.acme.logback.ReqIdConverter"/>
<appender name="mdcDemo" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>localhost</syslogHost>
<facility>LOCAL0</facility>
<suffixPattern>%mdc{reqId} - %message</suffixPattern>
</appender>
<logger name="com.acme.service" level="TRACE">
<appender-ref ref="mdcDemo"/>
</logger>
<!-- MDC 的另一种使用方式:通过配置文件 -->
<appender name="mdcDemo2" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>localhost</syslogHost>
<facility>LOCAL0</facility>
<suffixPattern>%X{reqId} - %message</suffixPattern>
</appender>
<logger name="com.acme.service2" level="TRACE">
<appender-ref ref="mdcDemo2"/>
</logger>
<!-- Logback Groovy 编写复杂的过滤条件 -->
<appender name="groovyDemo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_DIR}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_DIR}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.core.filter.Filter">
<groovy>
def mdc = event.getMDC()
if (mdc == null) {
return FilterReply.NEUTRAL
}
def user = mdc.get("user")
if (user == null || !user.equals("admin")) {
return FilterReply.DENY
}
return FilterReply.ACCEPT
</groovy>
</filter>
</appender>
<logger name="com.mypackage2" level="debug">
<appender-ref ref="groovyDemo"/>
</logger>
<!-- JMX 监控,可以在 JConsole 或者 JVisualVM 中查看 -->
<jmxConfigurator/>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>
<!-- 日志分离存储 -->
<appender name="dbAppender" class="com.example.logback.appender.DBAppender">
<connectionSource class="com.example.logback.datasource.DataSourceConnectionSource">
<url>jdbc:mysql://localhost:3306/dbname</url>
<user>username</user>
<password>password</password>
<driverClass>com.mysql.jdbc.Driver</driverClass>
<minConnectionsPerPartition>5</minConnectionsPerPartition>
<maxConnectionsPerPartition>20</maxConnectionsPerPartition>
<partitionCount>2</partitionCount>
</connectionSource>
<bufferSize>1000</bufferSize>
<tableName>logs</tableName>
<columns>
<column name="timestamp" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}" />
<column name="level" pattern="%level" />
<column name="logger" pattern="%logger" />
<column name="message" pattern="%message" />
</columns>
</appender>
<logger name="com.example.myapp" level="INFO">
<appender-ref ref="asyncAppender"/>
<appender-ref ref="dbAppender"/>
</logger>
</configuration>
此份 Logback 配置有以下功能:
- 按大小和日期拆分的文件输出:可以通过配置文件来实现,比较灵活;
- 根据系统环境变量动态配置日志级别:可以根据环境变量的值来决定输出的日志级别;
- MDC(Mapped Diagnostic Context):通过为每个线程关联一个 Map 来实现在日志输出中添加自定义的上下文信息,例如请求 ID、用户信息等;
- 可以通过配置文件或者编写 Java 类来使用 MDC;
- 可以通过 Groovy 或者 JavaScript 等脚本语言来编写复杂的过滤条件,可以根据日志事件中的任意字段来决定是否输出;
- JMX 监控:可以在 JConsole 或者 JVisualVM 中查看 Logback 使用情况和日志输出;
- 日志分离存储:将日志输出到数据库中。
需要注意的是,上述配置代码的变量值和路径都是示例,实际使用时需要根据实际情况进行修改。
更多推荐
所有评论(0)