系列文章
前言
先阅读Java核心技术-日志(上) 文章,了解整个Java系统的发展历史以及目前的现状,在前一篇文章中介绍了JCL+(Log4j,JUL)
组合。本文介绍SLF4J+Logback
组合。
Logback
Logback
是由Log4j
创始人设计的另一个开源日志组件,继承自Log4j
。目前最新版本1.2.11
,Logback
分为三个不同的模块:
模块 | 功能 |
---|---|
logback-core | 其它两个模块的基础 |
logback-classic | log4j 的一个优化版本,完整实现SLF4J API |
logback-access | 与Servlet 容器集成提供通过Http来访问日志的功能 |
一、架构
Logback
主要由下面三部分组成:
Logger
—— 日志记录器,定义日志类型、级别,属于logback-classic 模块。
Appender
—— 指定日志的输出方式和目的地,属于logback-core 模块。
Layout
—— 格式化日志信息,属于logback-core 模块。
由于logback-classic
实现了原生的SLF4J API
,所以Logback
的一般使用方式是 slf4j-api
+ logback-classic
的形式。
1.Logger
Logger
作为日志的记录器,把它关联到应用的对应的LoggerContext
上后存放日志对象,也可以定义日志类型、级别。
通过 LoggerFactory.getLogger() 可以获取到具体的 logger 实例,名字相同则返回的 logger 实例也相同。由于logback实现了slf4j,因此使用slf4j的Logger抽象类,和工厂类即可
Logger x = LoggerFactory.getLogger(“test-logback”);
Logger y = LoggerFactory.getLogger(“wombat”);
x,y 是同一个 logger 对象。
2.Appender
Appender
主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL
、PostreSQL
、 Oracle
和其他数据库、 JMS
和远程UNIX Syslog
守护进程等。
3.Layout
Layout
负责把事件转换成字符串,格式化的日志信息的输出。
4.LoggerContext
每个Logger
都被关联到一个 LoggerContext
,LoggerContext
负责创建Logger
,也负责以树结构排列各Logger
。
Logback
执行流程:
二、日志级别
Logback
级别定义在:org.slf4j.event.Level
。
package org.slf4j.event;
public enum Level {
ERROR(40, "ERROR"),
WARN(30, "WARN"),
INFO(20, "INFO"),
DEBUG(10, "DEBUG"),
TRACE(0, "TRACE");
}
日志级别优先级:TRACE
< DEBUG
< INFO
< WARN
< ERROR
三、 配置文件
Logback
查找配置的顺序如下所示:
1.在系统配置文件System Properties
中寻找是否有logback.configurationFile
对应的value
2.在classpath
下寻找是否有logback-test.xml
3.在classpath
下寻找是否有logback.groovy
(即logback
支持groovy
与xml
两种配置方式)
4.在classpath
下寻找是否有logback.xml
如果配置文件 logback-test.xml
和 logback.groovy
,logback.xml
都不存在,那么 logback 默认配置,它是一个关联到Root Logger
的ConsoleAppender
组成。输出用模式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
的 PatternLayoutEncoder
进行格式化。Root Logger
默认级别是 DEBUG
。
接下来测试下默认配置:
添加maven
依赖
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
测试程序,不添加任何配置:
package com.laopeng301;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest
{
public static void main(String[] args) {
Logger logger= LoggerFactory.getLogger(LogbackTest.class);
logger.info("info测试默认配置");
logger.trace("trace默认配置不输出");
}
}
15:02:50.304 [main] INFO com.laopeng301.LogbackTest - info测试默认配置
由于默认配置的日志级别是DEBUG
,所以trace
日志不会打印。
logback.xml常用配置
Logback配置文件非常的灵活,整个配置文件结构:
<configuration>
开头,后面有零个或多个<appender>
元素,有零个或多个<logger>
元素,有最多一个<root>
元素。
<Configuration scan="true" scanPeriod="60 seconds" debug="false">
<Property name="app-name" value="logback-test" />
<ContextName>${app-name}</ContextName>
<Appender>
</Appender>
<Logger>
</Logger>
<Root>
</Root>
</Configuration>
Configuration
<configuration scan="true" scanPeriod="60 seconds" debug="false">
</configuration>
参数 | 说明 |
---|---|
scan | 设置为true 时,配置文件如果发生改变,将会被重新加载,默认值为true |
scanPeriod | 监测配置文件是否有修改的时间间隔,没有给出时间单位,默认单位是毫秒。当scan 为true 时,此属性生效。默认的时间间隔为1分钟 |
debug | 设置为true时,将打印出logback 内部日志信息,默认false |
Property & ContextName &Timestamp
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<Property name="app-name" value="logback-test" />
<ContextName>${app-name}</ContextName>
<Timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
</configuration>
Property
:定义变量,两个属性name
和value
,<Property>
定义的值会被插入到Logger
上下文中,可以使“${}
”来使用变量。ContextName
:设置上下文名称,每个Logger
都关联到Logger
上下文,默认上下文名称为default
<Timestamp>
:获取时间戳字符串,两个属性key
(标示名称),datePattern
(格式化SimpleDateFormat
)。
Appender
负责写日志的组件,它有两个必要属性name
和class
。name
指定Appender
名称,class
指定Appender
的全限定名。例如:ch.qos.logback.core.ConsoleAppender
ConsoleAppender
控制台输出日志
<Configuration scan="true" scanPeriod="60 seconds" debug="false">
<Property name="app-name" value="logback-test" />
<ContextName>${app-name}</ContextName>
<Timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<Appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">
<Encoder>
<Pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</Pattern>
<Target>System.out</Target>
</Encoder>
</Appender>
<Root level="DEBUG">
<Appender-ref ref="CONSOLE-LOG"></Appender-ref>
</Root>
</Configuration>
<Encoder>
:对日志进行格式化
<Target>
:字符串System.out(默认)或者System.err
FileAppender
把日志记录到文件
<Appender name="FILE-LOG" class="ch.qos.logback.core.FileAppender">
<File>testFile.log</File>
<Append>true</Append>
<Encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</Encoder>
</Appender>
<File>
:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
<Append>
:true
,日志被追加到文件结尾, false
,清空现存文件,默认是true
。
<Encoder>
:对日志进行格式化
<Prudent>
:如果是 true
,日志会被安全的写入文件,即使其他的FileAppender
也在向此文件做写入操作效率低,默认是 false
。
RollingFileAppender
滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件
1.TimeBasedRollingPolicy 时间滚动策略
<Çonfiguration>
<Appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--被写入的文件名-->
<File>test.log</File>
<!--日志追加到文件结尾 -->
<Append>true</Append>
<!--日志内容格式化 -->
<Encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</Encoder>
<!--发生滚动式,决定RollingFileAppender的行为,文件移动和命名,
class定义滚动策略 TimeBasedRollingPolicy时间滚动策略 -->
<RollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--滚动生成文件名的规则-->
<FileNamePattern>tests.%i.log.zip</FileNamePattern>
<!--保留归档文件的最大数量,超出数量删除旧文件。-->
<MaxHistory>7</MaxHistory>
</RollingPolicy>
</Appender>
<Root level="DEBUG">
<appender-ref ref="FILE" />
</Root>
</Çonfiguration>
上述配置表示每天生成一个日志文件,保存7天的日志文件。
2.FixedWindowRollingPolicy 固定窗口滚动策略
<Configuration>
<Appender name="FILE" 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>5MB</maxFileSize>
</TriggeringPolicy>
<Encoder>
<Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>
</Encoder>
</Appender>
<Root level="DEBUG">
<Appender-ref ref="FILE" />
</Root>
</Configuration>
上述配置表示按照固定窗口模式生成日志文件,当文件大于5MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。
以上是常用的Appender
,需要了解其它的可以参考官网。
Logger
用来设置某一个包或具体的某一个类的日志打印级别、以及指定<Appender>
<Logger name="类或者包" level="INFO" additivity="true">
<Appender-ref ref="FILE" />
<Appender-ref ref="CONSOLE" />
</Logger>
name
:用来指定受此Logger
约束的某一个包或者具体的某一个类。
level
: 用来设置打印级别
additivity
: 是否向上级Logger
传递打印信息。默认是true
Appender-ref
:标识这个Appender
将会添加到这个Logger
。
例如:
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
Root
Root Logger是所有<Logger>
的上级
<Root level="DEBUG">
<Appender-ref ref="FILE" />
<Appender-ref ref="CONSOLE" />
</Root>
四、 配置文件
1.添加maven
依赖
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
2.新增配置文件:src/resource/logbackxml
<Configuration scan="true" scanPeriod="60 seconds" debug="false">
<Property name="app-name" value="logback-test" />
<ContextName>${app-name}</ContextName>
<Timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<Appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">
<Encoder>
<Pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</Pattern>
<Target>System.out</Target>
</Encoder>
</Appender>
<Appender name="FILE-LOG" class="ch.qos.logback.core.FileAppender">
<File>testFile.log</File>
<Append>true</Append>
<Encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</Encoder>
</Appender>
<Root level="INFO">
<Appender-ref ref="CONSOLE-LOG"></Appender-ref>
</Root>
</Configuration>
3.测试类
package com.laopeng301;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackTest
{
public static void main(String[] args) {
Logger logger= LoggerFactory.getLogger(LogbackTest.class);
logger.info("info日志测试");
logger.trace("trace在info级别不输出");
}
}
185 [main] INFO com.laopeng301.LogbackTest - info测试默认配置
SLF4J
SLF4J即简单日志门面(Simple Logging Facade for Java)作为各种日志框架的简单Facade或抽象,例如:java.util.logging
, logback
和 reload4j(log4j)
。
对于一般日志框架会选择slf4j-api
作为门面,配上具体的实现框架(log4j
、logback
等),中间使用桥接器完成桥接。
1.单独SLF4J
单独slf4j-api是没有日志打印的效果,底层没有绑定具体的日志框架。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4JTest {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(SLF4JTest.class);
logger.info("test");
}
}
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
2.SLF4J+logback
底层绑定logback日志实现框架
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
执行上述测试程序:
16:53:47.667 [main] INFO com.laopeng301.SLF4JTest - test
3.SLF4J+reload4j(Log4j)
底层绑定Log4j日志实现框架
<dependencies>
<!--reload4j适配器(包含slf4j-api)-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
<version>1.7.36</version>
</dependency>
<!--reload4j(原名Log4j)-->
<dependency>
<groupId>ch.qos.reload4j</groupId>
<artifactId>reload4j</artifactId>
<version>1.2.18.5</version>
</dependency>
</dependencies>
新增配置 src/resource/log4j.properties
log4j.rootLogger=DEBUG,console
#输出到控制台
log4j.appender.console=org.apache.log4j.ConsoleAppender
#设置输出样式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#日志输出信息格式为
log4j.appender.console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
执行上述测试代码:
2022-04-27 16:58:48,165 [main] INFO [com.laopeng301.SLF4JTest] - test
4.SLF4J+JUL
底层绑定Java自带的JUL日志实现框架
<!--JUL适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.36</version>
</dependency>
执行测试代码:
4月 27, 2022 5:00:16 下午 com.laopeng301.SLF4JTest main
信息: test
5.SLF4J+Simple
底层绑定`SLF4J`官方推出的基本日志实现框架
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!--基本的日志实现,-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
[main] INFO com.laopeng301.SLF4JTest - test
6.SLF4J+nop
关闭一切日志输出信息
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.35</version>
</dependency>
7.SLF4J+LOG4J2
<!--Log4j2自带的日志门面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<!--Log4j2具体的日志实现-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<!--导入slf4j日志的门面(最终这个案例的日志实现是log4j2) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!--为slf4j绑定日志实现 log4j2的适配器 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
</dependency>
2022-04-27 18:36:42,936 [main] INFO SLF4JTest - test