Logback
1,什么是Logback
Logback是由log4j(先)创始人设计的又一个开源日志组件。
日志:程序记录在某个地方的一些信息。
2,为什么要记录日志
开发的程序上线之后一般要做两个事情:
- 用来跟踪定位程序的运行状态
- 用来快速的定位bug
日志框架有很多,比如log4j,log4j2等,logback是springboot默认自带的日志框架。以后使用springboot时会经常使用到。
3,Logback的主要组成部分
logback主要由三个模块组成:
- logback-access:logback-access模块与Servlet容器(如tomcat)集成,以提供http访问日志功能。可以使用这个模块来替换tomcat的访问日志。
- logback-classic:log4j的一个改良版本,同时它提供了完整的slf4j API,可以很方便的更换成其他日志系统如log4j。
- logback-core:其他两个模块的基础模块
ps:slf4j可以称之为门面日志接口,它提供了一套标准的日志功能的接口,没有任何的实现。而log4j和logback都是属于slf4j的具体实现。
4,Logback主要标签
logback主要用到的标签有三个:
- logger:日志记录器,用于存放日志对象,定义日志的类型和级别等。
- appender:用于指定日志输出的目的地,也就是日志存放的媒介,这个媒介可以是控制台,可以是文件,也可以是远程套接字服务器。
- layout:用来格式化日志信息的输出
对于日志框架来说,日志是有级别的,logback的日志级别:
trace(追踪) < debug(调试) < info(记录信息) < warn(警告) < error(错误)
在记录日志时,一般需要用到一个Logger类的对象,然后可以调用:logger.debug("xxx")、logger.info("xxx")...等方法。
如果记录的日志级别是info的话,info是大于debug和trace的,这个时候调用debug和trace方法记录的日志是无法显示的,而调用warn和error是可以显示的。
一般情况下,只需要记录debug、info和error的日志就行了,而这三个级别的日志需要放在不同的文件中。
5,Logback的具体配置
1,首先引入对应的包:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>
上面是直接在对应工程里引入。
如果有父工程的话可以先在父工程引入:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后在子工程里具体的引入,这个时候就不需要写版本号和有效范围了:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
2,创建logback的配置文件,文件名就叫做logback.xml:
首先,我们的logback的配置文件可以在我们运行java程序的时候就指定好:
java -Dlogback.configurationFile=xxxxx/xxxx.xml
但是如果没有指定,那么logback会自动去加载classpath下面logback.grovvy文件。如果这个文件找不到,那么它会自动的加载classpath下面的logback-test.xml文件。如果文件也没有,那会自动加载classpath下面的logback.xml文件,所以就直接取名logback.xml。
对应的配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!--
configuration:logback的根标签
scan="true":表示配置文件发生了改变会自动加载
scanPeriod="60 seconds":检测配置文件修改的时间间隔,默认单位是毫秒
debug:这个属性如果为TRUE,表示会打印出logback自身实时的运行信息。因为logback自身运行是非常稳定的,所以这里就设置为FALSE,相信logback就好了
-->
<configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="logback.xsd"
scan="true"
scanPeriod="60 seconds"
debug="false">
<!--定义一些参数常量-->
<property name="log.filepath" value="E:\\softdata\\logback\\logTest"/><!--定义日志的输出位置(文件)-->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{100} %msg%n"/><!--定义日志展示的格式-->
<!--定义日志输出的媒介-->
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><!--定义控制台输出,class指定具体输出位置要使用的类-->
<!--appender是负责统一调度日志的输出工作,具体的日志格式化和输出工作会交给encoder-->
<encoder>
<pattern>${log.pattern}</pattern><!--定义日志输出的格式-->
</encoder>
</appender>
<!--定义不同级别的日志的输出的媒介-->
<!--定义debug级别的日志输出-->
<appender name="debugAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--RollingFileAppender:表示滚动日志,可以按天或月来生成不同的日志文件-->
<file>${log.filepath}/debug.log</file><!--文件存放路径-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置按每分钟的方式生成文件,如果文件结尾是.gz,那么logback会自动把日志文件压缩,压缩前后的日志文件大小差异还是很大的-->
<fileNamePattern>${log.filepath}/debug-%d{yyyy-MM-dd_HH_mm}.log.gz</fileNamePattern><!-- 要设置按天的方式生成文件的话,把_HH_mm删掉就好 -->
<maxHistory>31</maxHistory><!--设置文件最大保存的历史数据-->
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern><!--定义日志输出的格式-->
</encoder>
<!--debugAppender只需要记录debug级别的日志,所以对于其他级别的日志直接过滤,要设置一个过滤器-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch><!--对于debug级别日志,同意记录-->
<onMismatch>DENY</onMismatch><!--对于其他级别日志,直接略过-->
</filter>
</appender>
<!--定义info级别的日志输出-->
<appender name="infoAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--RollingFileAppender:表示滚动日志,可以按天或月来生成不同的日志文件-->
<file>${log.filepath}/info.log</file><!--文件存放路径-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置按每分钟的方式生成文件,如果文件结尾是.gz,那么logback会自动把日志文件压缩,压缩前后的日志文件大小差异还是很大的-->
<fileNamePattern>${log.filepath}/info-%d{yyyy-MM-dd_HH_mm}.log.gz</fileNamePattern>
<maxHistory>31</maxHistory><!--设置文件最大保存的历史数据-->
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern><!--定义日志输出的格式-->
</encoder>
<!--debugAppender只需要记录info级别的日志,所以对于其他级别的日志直接过滤,要设置一个过滤器-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch><!--对于info级别日志,同意记录-->
<onMismatch>DENY</onMismatch><!--对于其他级别日志,直接略过-->
</filter>
</appender>
<!--定义error级别的日志输出-->
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--RollingFileAppender:表示滚动日志,可以按天或月来生成不同的日志文件-->
<file>${log.filepath}/error.log</file><!--文件存放路径-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置按每分钟的方式生成文件,如果文件结尾是.gz,那么logback会自动把日志文件压缩,压缩前后的日志文件大小差异还是很大的-->
<fileNamePattern>${log.filepath}/error-%d{yyyy-MM-dd_HH_mm}.log.gz</fileNamePattern>
<maxHistory>31</maxHistory><!--设置文件最大保存的历史数据-->
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern><!--定义日志输出的格式-->
</encoder>
<!--debugAppender只需要记录error级别的日志,所以对于其他级别的日志直接过滤,要设置一个过滤器-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch><!--对于error级别日志,同意记录-->
<onMismatch>DENY</onMismatch><!--对于其他级别日志,直接略过-->
</filter>
</appender>
<!--配置根日志记录器,所有包下面的日志都会被记录-->
<root level="DEBUG">
<appender-ref ref="consoleAppender"/>
</root>
<!--配置代码的日志记录器-->
<logger name="com.xl.logback.TestLog" level="DEBUG" additivity="true">
<!-- name="com.xl.logback":表示对应包里的类里面(包含子包)的代码产生的日志才会被下面的记录器记录,否则不会
additivity="true":表示自定义的记录器日志输出
level="DEBUG" :日志级别,如果不设置,则自动继承根记录器
-->
<appender-ref ref="debugAppender"/>
<appender-ref ref="infoAppender"/>
<appender-ref ref="errorAppender"/>
</logger>
</configuration>
以上。
6,Logback程序中使用
package com.xl.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
public class TestLog {
public static void main(String[] args) throws InterruptedException {
Logger logger = LoggerFactory.getLogger(TestLog.class);
Random r = new Random();
while (true) {
int a = r.nextInt();
if (a % 5 == 0) {
logger.trace("trace: num is " + a);
} else if (a %5 == 1) {
logger.debug("debug: num is " + a);
} else if (a %5 == 2) {
logger.info("info: num is " + a);
} else if (a %5 == 3) {
logger.warn("warn: num is " + a);
} else if (a %4 == 3) {
logger.error("error: num is " + a);
}
Thread.sleep(100);
}
}
}
使用比较简单,重点还是在配置部分。
7,root标签日志级别设置无效问题
1,首先把root的级别设置为info:
<root level="INFO"> <appender-ref ref="consoleAppender"/> </root>
2,然后在程序里面全部用debug来记录日志:
logger.debug("debug a = "+a);
此时,按理来说是不应该再输出的。但是结果:
还是全部输出了...
这种情况是因为底层的日志记录器会自动的向上层抛出日志。比如说我自定义了一个记录器,级别是debug,它会自动抛给上层root记录器,而不去管root的级别。
这个时候,如果不想要debug的日志,可以直接在consoleAppender里配置一个filter:
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"><!--定义控制台输出,class指定具体输出位置要使用的类-->
<!--appender是负责统一调度日志的输出工作,具体的日志格式化和输出工作会交给encoder-->
<encoder>
<pattern>${log.pattern}</pattern><!--定义日志输出的格式-->
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>