Java 的日志框架 logback
# Java 的日志框架 Logback
Logback (opens new window) 是 Java 应用程序的日志框架,作为著名的 Log4j (opens new window) 项目的后续。事实上,它们都是同一班人马的作品。日志,作为任何 Java 企业级应用程序的基础功能,其重要性和必要性不言而喻。选择 Logback 作为日志框架,有几个原因:
- 比 Log4j 速度更快
- 原生支持 SLF4J (opens new window),这使得我们可以轻松地在不同的日志框架里切换,如若后期有这个必要的话。
- 高级的过滤功能
- 日志文件大小、个数的限制,以及压缩
- 从 I/O 错误中恢复
Logback 项目组织成了3个模块:
- logback-core,它包含了基本的日志功能
- logback-classic,它多了一些增强功能,例如 sl4j 的支持
- logback-access,它提供了与 Servlet 容器的整合,如 Tomcat 和 Jetty
下面,我们看怎么在 Java 应用程序里面使用它。这里以最常用的 logback-classic 为例。
# Maven 依赖
在 Java 项目的 Maven 配置文件 pom.xml
中,先定义了2个相关的版本属性:
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<slf4j.version>1.7.30</slf4j.version>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<logback-classic.version>1.2.3</logback-classic.version>
上面注释中的 URL 可以查看并使用最新的版本。
再定义 jar 包依赖,使用上面定义好的版本属性参数。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback-classic.version}</version>
</dependency>
# Logback 基本配置
配置 Logback 可以用 XML 或者 Groovy,它将按照命名规范自动寻找配置文件。有三个合法的配置文件,Logback 将按顺序来查找:
- logback-test.xml
- logback.groovy
- logback.xml
注意: 在 Java 项目中,我们通常有2个 resources 文件夹,分别是
src/main/resources
和src/test/resources
。我们创建2个配置文件,分别是src/main/resources/logback.xml
和src/test/resources/logback-test.xml
。这样,在开发时,Logback 会使用logback-text.xml
作为配置文件;而生产时,因为发行包在构建时会舍弃src/test
文件夹,只能找到并使用logback.xml
。从而可以很容易做到开发和生产环境的2套不同配置。
下面的例子中,我将以 logback.xml
为例,讲述它的配置。
最简单的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出格式 -->
<pattern>%date [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志级别: off, trace, debug, info, warn, error -->
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
上面定义了一个名为 STDOUT (控制台输出)的 appender,将 root (根)日志对象指向它,日志输出级别定义为 debug。它的输出例子如下:
2020-04-14 11:35:47,778 [main] DEBUG com.example.springmvc.controller.HomeController - Some log message.
我们可以在 <configuration>
上添加2个可选参数:
增加一个 scan 参数:
<configuration scan="true"> ... </configuration>
它可以让 Logback 以默认值每分钟一次的频率来扫描配置文件,如果有改动将重新载入生效。您可以再增加一个参数,修改此扫描频率,例如设定30秒扫描一次:
scanPeriod="30 seconds"
增加一个 debug 参数:
<configuration debug="true"> ... </configuration>
这个参数在调试本配置文件时特别有用,它能够让 Logback 在初始化时,在控制台打印出加载的配置详细信息,方便我们找到配置错误。
我们还可以定义一些变量,或是通过外部的属性文件载入多个变量。在配置时引用这些变量,可以让配置文件更加灵活。例如:
定义了一个变量
fileName
,它将在后面用来定义日志文件名。<property name="fileName" value="file.log" />
通过一个外部资源文件 “application.properties” 来载入其中定义的多个变量。
<property resource="application.properties" />
这个资源文件
application.properties
的内容如下例,在其中定义了多个变量:# Application Name, it is used for log filename. AppName=Spring4MVCHelloWorldDemo # Application version. AppVersion=1.0.0 # Application log directory. AppLogDir=logs
定义了变量后,我们就可以在配置文件中使用它,例如:
<file>${fileName}</file>
这里使用了 fileName 变量,用它来设定日志的文件名。
# Logback 实用配置
下面给出一个相对实用的配置。
# 1. 控制台的日志
<configuration debug="false" scan="true">
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 带颜色加亮的输出格式 -->
<pattern>%date %highlight(%-5level) [%thread] [%file:%line] - %msg%n%ex{full}</pattern>
<!-- 普通的输出格式 -->
<!-- <pattern>%date %-5level [%thread] [%file:%line] - %msg%n%ex{full}</pattern> -->
</encoder>
</appender>
<!-- 日志级别: off, trace, debug, info, warn, error -->
<root level="error">
<appender-ref ref="consoleAppender"/>
</root>
</configuration>
这里我们定义了 consoleAppender 输出对象,并将 root (根)日志对象指向它,从而实现了控制台日志输出。
这里的 <pattern>
里使用了 logback 的一个特性——将不同的日志级别突出,用不同的颜色显示。例如,在 Windows 上用 Maven 启动了此 Web 应用程序 (mvn jetty:run
),我们从控制台可以看到如下的日志输出效果:
在图中我们可以看到,错误(ERROR)级别的日志是红色突出显示,更方便我们注意到问题。
# 2. 滚动文件日志
日志通常都是以日志文件形式保存起来,并且保存一段时间。例如我们设定为30天,每天生成并保存一个日志文件(文件名中含有日期),30天之后,新生成一个日志文件之后,再将最早期的一个日志文件删除。这就是“滚动文件”(rolling file)的意思。下面我们将配置一个滚动文件的日志,它将按天输出日志,并将旧日志文件压缩存档,节省硬盘存储空间。
<configuration debug="false" scan="true">
<!-- 日志输出的设置 -->
<property name="LOG_PATH" value="logs"/>
<property name="LOG_ARCHIVE" value="${LOG_PATH}/archive"/>
<property name="LOG_FILENAME" value="SpringMVCHelloWorld"/>
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志文件名 -->
<file>${LOG_PATH}/${LOG_FILENAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_ARCHIVE}/${LOG_FILENAME}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!-- 每个归档文件的最大上限 -->
<maxFileSize>10MB</maxFileSize>
<!-- 全部归档文件的最大上限,超过后将会被删除 -->
<totalSizeCap>20GB</totalSizeCap>
<!-- 最长保留的历史 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<!-- 使用 UTF-8 编码,用于在日志中写入中文信息 -->
<charset>UTF-8</charset>
<!-- 日志输出格式 -->
<pattern>%date %-5level [%thread] [%file:%line] - %msg%n%ex{full}</pattern>
</encoder>
</appender>
<!-- 日志级别: off, trace, debug, info, warn, error -->
<logger name="com.example.springmvc" level="trace" additivity="false">
<appender-ref ref="fileAppender"/>
<appender-ref ref="consoleAppender"/>
</logger>
</configuration>
这里我们定义了 fileAppender 输出对象,并将 com.example.springmvc(本应用程序的包名)日志对象指向它,同时也向控制台输出,从而实现了滚动文件日志输出。
# Logback 的使用
我们通过 SLF4J 的 API 来使用它,用起来很简单。按日志级别来输出信息即可,它们分别是:trace、debug、info、warn,和 error。
先获得 Logger 对象。这里通过类名按静态对象来初始化它:
package com.example.springmvc.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
...
}
然后,在需要日志输出的地方,使用此 Logger 对象来输出日志:
logger.trace("This is a level below debug, tracing down the error in detailed steps.");
if (logger.isDebugEnabled()) {
logger.debug("This is a debug message from HomeController.index() method, param1={}, param2={}", 123, 456);
}
logger.info("Some general information.");
logger.warn("A warning message means somethings need your attention.");
if (logger.isErrorEnabled()) {
logger.error("one two three: {} {} {}", "a", "b", "c",
new RuntimeException("something went wrong"));
}
上例中,为了避免降低执行效率,可以先判断是否此级别的日志允许输出,然后再调用相应的级别 API 输出日志信息。请注意示例代码中如何使用参数,以及异常对象来作为日志输出。
关于如何格式化日志信息,包括使用参数,对象数组,以及异常对象,还可以参考 StackOverflow 的一篇帖子: slf4j: how to log formatted message, object array, exception (opens new window)
# 小结
上面介绍了 Logback 的配置和使用,并给出了一个实用的,可用于生产的配置,方便感兴趣的开发人员参考。
下面的参考链接里,还讲述了其它一些高级功能的使用,例如让日志文件根据用户或者级别来分开,在输出错误日志时发送电子邮件等。
参考链接: