使用logback日志框架
1. logback日志概述
在项目开发中,日志十分的重要,不管是记录运行情况还是定位线上问题,都离不开对日志的分析。日志记录了系统行为的时间、地点、状态等相关信息,能够帮助我们了解并监控系统状态,在发生错误或者接近某种危险状态时能够及时提醒我们处理,同时在系统产生问题时,能够帮助我们快速的定位、诊断并解决问题。
Logback是一个开源的日志记录组件,使用非常的广泛。Logback是由Log4j的创始人重新设计的一个现代化的日志框架,是SLF4J的原生实现。
logback主要由三个模块组成,分别是logback-core,logback-classic和logback-access。其中logback-core是整个Logback的核型模块,logback-classic支持了SLF4J FACADE,而logback-access则集成了Servlet容齐来提供HTTP日志功能,适用于web应用。
2. 日志概念
2.1 日志信息的优先级
日志信息的优先级从高到低有TRACE < DEBUG < INFO < WARN < ERROR < FATAL
- TRACE:追踪,是最低的日志级别,相当于追踪程序的执行
- DEBUG:调试,一般在开发中,都将其设置为最低的日志级别
- INFO:信息,输出重要的信息,使用较多
- WARN:警告,输出警告的信息
- ERROR:错误,输出错误信息
- FATAL:严重错误
这些级别分别用来指定这条日志信息的重要程度;级别高的会自动屏蔽级别低的日志,也就是说,设置了WARN的日志,则INFO、DEBUG的日志级别的日志不会显示。
2.2 日志输出
日志信息的输出目的地指定了日志将打印到控制台还是文件中;
2.3 日志输出格式
输出格式则控制了日志信息的显示内容。
3. 引入logback依赖
xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
</dependency>
4. 配置文件结构
Logback的配置文件通常是XML格式,文件名为logback.xml。它的结构如下:
- configuration:配置文件的根元素,它包含了多个子元素:appender、logger和root
- appender:定义了输出端,可以是控制台、文件、网络等,每一个appender都需要有一个唯一的名称和一个类定义
- logger:定义了日志记录器,用于记录指定类的日志信息。logger元素需要指定一个名称和一个级别,以及一个可选的appender-ref子元素,用于将日志记录器连接到一个appender
- root:定义了根日志记录器,它会接收所有未被其他logger接收的日志事件
xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--
定义变量值的标签,property标签有两个属性,name和value;过property定义的值会被插入到logger上下文中。定义变量后,可以使${name}来使用变量
-->
<property name="AppName" value="demo"/>
<!--
每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用contextName标签设置成其他名字,用于区分不同应用程序的记录
-->
<contextName>${AppName}</contextName>
<!--负责写日志的组件-->
<appender>
</appender>
<!--用来设置某一个包或者具体的某一个类的日志打印级别以及指定appender。-->
<logger>
<appender-ref ref="spring6log"/>
</logger>
<!---根logger,也是一种logger,且只有一个level属性-->
<root>
</root>
</configuration>
4. 记录器logger
4.1 记录器的属性
记录器有三个属性:
- name属性:记录器的名字(一般设置为当前类的全类名)
- level属性(可选):
- 记录器的级别,从低到高:TRACE < DEBUG < INFO < WARN < ERROR < FATAL
- 假设当前记录器级别为INFO那么只能打印级别打印等于INFO的记录
- 如果记录器未设置level属性,则该记录器的级别从上级记录器继承
- root(根记录器只有level属性)
- additivity属性(可选):
是否允许叠加打印日志true/false,就说如果你通过上图的org.example.APP打印日志,那么他上分所有的日志记录器都会执行,这就是叠加打印。默认false
5. 附加器Appender
记录器会将输出日志的任务交给附加器完成,不同的附加器会将日志输出到不同的地方,比如控制台附加器、文件附加器、网络附加器等等。常用的附加器:
- 控制台附加器:ch.qos.logback.core.ConsoleAppender
- 文件附加器:ch.qos.logback.core.FileAppender
- 滚动文件附加器:ch.qos.logback.core.rolling.RollingFileAppender
6. 示例配置
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="LOG_CONTEXT_NAME" value="web-app"/>
<!--定义日志文件的存储地址 勿在LogBack的配置中使用相对路径-->
<property name="LOG_HOME" value="logs/${LOG_CONTEXT_NAME}"/>
<!-- 定义日志上下文的名称 -->
<contextName>${LOG_CONTEXT_NAME}</contextName>
<!--定义了输出日志的格式到log的格式-->
<property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n"/>
<!--定义了输出日志的格式到html的格式-->
<property name="pattern-html" value="%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c%M%L%thread%m"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象 默认 System.out(黑色) 改为 System.err(红色)-->
<target>System.out</target>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>${pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<!--日志级别过滤器LevelFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!--info日志统一输出-->
<appender name="file.info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--启用审慎模式:当启用审慎模式时,Logback会确保在多进程或多实例环境中,多个进程或实例可以安全地共享同一个日志文件。-->
<Prudent>true</Prudent>
<!--日志拆分规则-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名,按小时生成输出log文件-->
<!--<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/info/info.%d{yyyy-MM-dd-HH}.%i.log</FileNamePattern>-->
<!--日志文件输出的文件名,按小时生成输出html文件-->
<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/info/info.%d{yyyy-MM-dd-HH}.%i.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!--日志文件不能超过10MB-->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!--日志消息格式配置-输出log文件-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出-->
<pattern>${pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 只记录INFO级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日志输出级别 -->
<root level="ALL">
<appender-ref ref="console"/>
<appender-ref ref="file.info"/>
</root>
<!-- 某类/包下的所有日志使用file.info appender输出-->
<!--<logger name="cn.ybzy.demo.controller.TestController" additivity="false">-->
<!-- <appender-ref ref="file.info"/>-->
<!--</logger>-->
<!--<logger name="org.hibernate.SQL">-->
<!-- <level value="DEBUG"/>-->
<!--</logger>-->
</configuration>
7. 测试
运行原测试程序:
8. 使用日志
修改HelloWorldTest代码:
java
public class HelloWorldTest {
private Logger logger = LoggerFactory.getLogger(HelloWorldTest.class);
@Test
public void testHelloWorld(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld helloworld = (HelloWorld) ac.getBean("helloWorld");
helloworld.sayHello();
logger.info("执行成功");
}
}
运行查看控制台: