一,Logback
1.1 概述
Logback 是由 Log4j 的创始人设计的一个现代化的日志框架,是 SLF4J 的原生实现。
- 特点:
- 高性能:采用异步日志机制,可以将日志操作和业务逻辑分离,从而大幅度提升系统的性能。
- 灵活的配置:支持多种不同的配置方式,包括基于XML、Groovy、JSON等格式的配置文件,同时还支持通过代码进行配置。
- 多种日志级别:支持6种不同的日志级别,包括TRACE、DEBUG、INFO、WARN、ERROR和FATAL,用户可以根据需要选择合适的日志级别。
- 多种输出方式:支持多种不同的输出方式,包括控制台输出、文件输出、邮件发送等。用户可以根据需要选择合适的输出方式。
- 插件丰富:提供许多有用的插件,例如logstash-logback-encoder,可以将日志输出到ELK(Elasticsearch、LogstashKibana)平台上进行分析和可视化。
- 易于集成:Logback与Spring、Hibernate、JUnit等框架都有很好的集成,可以方便地进行应用程序的日志输出管理。
1.2 配置文件结构
Logback 的配置文件通常是 XML 格式,文件名为 logback.xml。它的结构如下:
- configuration : 配置文件的根元素,它包含了多个子元素:appender、logger 和 root
- appender : 定义了输出端,可以是控制台、文件、网络等,每一个appender都需要有一个唯一的名称和一个类定义
- logger : 定义了日志记录器,用于记录指定类的日志信息。logger元素需要指定一个名称和一个级别,以及一个可选的appender-ref子元素,用于将日志记录器连接到一个appender
- root : 定义了根日志记录器,它会接收所有未被其他logger接收的日志事件
<!--
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=""/>
</logger>
<!---根logger,也是一种logger,且只有一个level属性-->
<root>
</root>
</configuration>
1.3 日志级别
- ALL:最低等级的,用于打开所有日志记录
- TRACE:是最详细的日志信息,通常用于诊断问题和追踪代码执行流程**。在生产环境中,应该关闭TRACE级别的日志输出,以避免影响系统性能**
- DEBUG:是调试信息,用于调试应用程序。在生产环境中,建议将DEBUG级别的日志输出关闭
- INFO:是普通的信息记录,通常用于向用户展示可读的操作结果或执行状态。例如,当用户成功登录时,可以记录一条 INFO 级别的日志
- WARN:表示警告信息,通常用于记录一些不严重但需要注意的问题。例如,当系统资源紧张时,可以记录一条WARN级别的日志
- ERROR:表示错误信息,通常用于记录系统运行时发生的错误。例如,当数据库连接失败时,可以记录一条ERROR级别的日志
- FATAL:表示致命错误,通常用于记录系统崩溃或无法恢复的错误。例如,当出现内存泄漏或硬盘损坏时,可以记录一条FATAL级别的日志
- OFF:最高等级的,用于关闭所有日志记录。
二,Logback快速入门
-
logback坐标
不写版本的原因是SpringBoot自带集成logback,只需引入即可
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>
如果引入了jdbc就不需要引入logback,jdbc里面引入了loback的
-
配置文件编写
springboot集成了logback日志系统**,默认读取名叫logback-spring.xml的配置文件**,如果想自定义配置文件的名称,需要在spring boot配置文件中配置指定
logging: config: classpath:logback.xml
-
用法:
public class MyTest { private static final Logger logger = LoggerFactory.getLogger(MyTest.class); public static void main(String[] args) { logger.info("info....."); logger.warn("warn" + "....."); logger.error("error,msg={}", "error...."); } }
-
与lombok集成
logback和lombok集成,使用@Slf4j注解标注类,直接使用log对象,需添加lombok依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
@Slf4j public class MyTest { public static void main(String[] args) { log.info("info....."); log.warn("warn" + "....."); log.error("error,msg={}", "error...."); } }
三,logback配置文件详解
logback组件之间的关系:
-
Logger:日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。
-
Appender:用于指定日志输出的目的地,目的地可以是控制台、文件、数据库等等。
-
Layout:负责把事件转换成字符串,格式化的日志信息的输出。在logback中Layout对象被封装在encoder中。
3.1 记录器logger
3.1.1 记录器的层级结构:
**记录器有一个默认的root(根记录器)**每当我们创建一个logger就会如下图的结构
3.1.2 记录器的属性
记录器有三个属性:
- name属性:记录器的名字(一般设置为当前类的全类名)
- level属性(可选):
- 记录器的级别,从低到高:TRACE<DEBUG<INFO<WARN<ERROR<FATAL
- 假设当前记录器级别为INFO那么只能打印级别打印等于INFO的记录
- 如果记录器未设置level属性,则该记录器的级别从上级记录器继承
- root(根记录器只有level属性)
- additivity属性(可选):
- 是否允许叠加打印日志true/false,就说如果你通过上图的org.example.APP打印日志,那么他上分所有的日志记录器都会执行,这就是叠加打印。默认false
配置文件举例:
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<logger name="com.aaa" level="info">
</logger>
</configuration>
3.2 附加器Appender
记录器会将输出日志的任务交给附加器完成,不同的附加器会将日志输出到不同的地方,比如控制台附加器、文件附加器、网络附加器等等。
常用的附加器:
- 控制台附加器:ch.qos.logback.core.ConsoleAppender
- 文件附加器:ch.gos logback.core.FileAppender
- 滚动文件附加器:ch.gos.logback.core.rolling.RollingFileAppender
3.2.1控制台附加器
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定义了输出日志的格式到log的格式-->
<property name="pattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--控制输出流对象 默认 System.out(黑色) 改为 System.err(红色)-->
<target>System.out</target>
<!--encoder中对日志进行格式化-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出-->
<pattern>${pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<logger name="org.hibernate.SQL">
<appender-ref ref="STDOUT"/>
</logger>
</configuration>
3.2.2 Pattern标签
-
在Pattern标签中使用**%作为转义字符**,如果要表达出%就使用%
-
%c{length}:输出日志的logger名,可有一个整形参数,功能是缩短logger名,设置为0表示只输入 logger最右边点符号之后的字符串。
- 如果logger名的长度>length:就输出简写内容
- 如果logger名的长度<length:就输出全部内容
- 相同的还有**%lo{length},%logger{length},%C{length},%class{length}**
-
%contextName
:输出上下文名称,默认是default需要在xml中添加标签
<contextName>这个是我的上下文名称</contextName>
-
%d{pattern}:输出当前时间,语法是yyyy-MM-hh HH:mm:ss.SS:年月日,时分秒毫秒
也可以写成**%date{pattern}**
-
%F或%File:输出当前执行这个log的java文件名(尽量避免使用)
-
%caller{depth}:输出生成日志的调用者的位置信息,整数选项表示输出信息的深度
-
%L或%line:输出执行日志请求的行号**(尽量避免使用)**
-
%m,%msg,%message:输出应用程序提供的信息(log.info("输出这里面的内容"))
-
%M,%method:输出执行日志请求的方法,(尽量避免使用)
-
%n:输出一个换行
-
**%p,%le,%level:**输出日志的级别
-
%r,%relative:输出从程序启动到创建日志记录的时间,单位是毫秒
-
**%t,%thread:**输出产生日志的线程名
-
%replace(p){r,t}:p为日志内容,r是正则表达式,将p中符合r的内容替换为t
举例:%replace(%msg){'\s' , test}
截取格式化:
-
%20logger:
举例:
- 假设logger内容长度为10,那么就会左边补齐10个空格
- 假设logger内容长度为23,那么就正常输出
-
%-20logger :第一个是补左侧,这个就是补右侧
-
%.20logger:
- 假设logger长度大于20,那么就只截取,从最右侧开始累计20个字符的内容
- 假设logger长度小于20,正常输出
-
%20.30logger:
- 如果logger长度小于20,先在左侧填满20,然后从最右侧开始截取
-
%-20.30logger:
- 如果logger长度小于20,先在右侧填满20,然后从最右侧开始截取
-
%-.20logger:
- 从左侧第一个开始计算,如果logger长度大于20,那么只截取到第20个字符
3.2.3 文件附加器
文件附加器有以下子标签:
-
file:文件名,可以是相对路径/绝对路径,如果上级路径不存在,就会自动创建,没有默认值。
-
append:文件是否追加,true是(默认),flase否
-
encoder:对记录事件进行格式化
-
prudent:根据不同类型有不同的效果
- FileAppender:如果是true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是false。
- RollingFileAppender:当为true时,不支持FixedwindowRollingPolicy。支持TimeBasedRollingPolicy,
但是有两个限制
-
不支持也不允许文件压缩
-
不能设置fil属性,必须留空。
-
layout和encoder的区别:白从0.9.19版本之后,Fileappender和他的子类是期望使用encoder,不再推荐使用layout。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定义了输出日志的格式到log的格式-->
<property name="pattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n"/>
<!-- 输出到文件 -->
<appender name="File" class="ch.gos logback.core.FileAppender">
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>${pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<!--输出到指定的mylog.log文件中-->
<file>mylog.log</file>
<!--默认true,代表每次将日志内容插入到mylog.log中,如果是false代表刷新-->
<append>true</append>
</appender>
<logger name="org.hibernate.SQL">
<appender-ref ref="File"/>
</logger>
</configuration>
3.2.4 滚动文件附加器
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定义了输出日志的格式到log的格式-->
<property name="pattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n"/>
<!-- 输出到文件 -->
<appender name="RollFile" class="ch.gos.logback.core.rolling.RollingFileAppender">
<!--输出到指定的mylog.log文件中-->
<file>mylog.log</file>
<!--日志消息格式配置-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>${pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<!--滚动策略 基于时间的-->
<rollingPolicy class="ch.gos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置归档文件的生成模式
yyyy-MM-dd就代表按天生成文件
yyyy-MM-dd HH就代表按小时
yyyy/yyyy-MM-dd HH就代表按小时生成文件,并将文件放到yyyy年这个文件夹中
-->
<fileNamePattern>%d{yyyy-MM-dd}.log</fileNamePattern>
<!--设置归档文件最大生成数量,超过的就删除旧的-->
<maxHistory>3</maxHistory>
<!--设置所有文件的总大小,超过就会删除超过的部分-->
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<!--滚动策略 基于时间和大小的-->
<rollingPolicy class="ch.gos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--设置归档文件的生成模式
yyyy-MM-dd就代表按天生成文件
yyyy-MM-dd HH就代表按小时
yyyy/yyyy-MM-dd HH就代表按小时生成文件,并将文件放到yyyy年这个文件夹中
-->
<fileNamePattern>%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!--设置归档文件最大生成数量,超过的就删除旧的-->
<maxHistory>3</maxHistory>
<!--设置所有文件的总大小,超过就会删除超过的部分-->
<totalSizeCap>5GB</totalSizeCap>
<!--文件超过50MB就归档为一个文件,这个是这个策略独有的-->
<maxFileSize>50Mb</maxFileSize>
</rollingPolicy>
</appender>
<logger name="org.hibernate.SQL">
<appender-ref ref="RollFile"/>
</logger>
</configuration>
目前有两种滚动策略:
基于时间的滚动策略
TimeBasedRollingPolicy
基于时间和大小的滚动策略
SizeAndTimeBasedRollingPolicy
3.3 过滤器
过滤器有很多,但只看:
-
LevelFilter:
<!-- 只记录INFO级别的日志 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>FATAL</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
-
ThresholdFilter:
<!-- 只有DEBUG及以上级别的才输出 --> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter>
在logback中,logger,layout,appender都可自己自定义写,写出自己需求的过滤器等,具体写法去看官网即可
3.4 示例配置
<?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>