Log日志
一、对比
Logger
Java util Logger是java原生的日志生成工具,不需要另外引用类库,使用方便,学习简单,能够在小型应用中灵活使用。
commons-logging
apache最早提供的日志的门面接口。避免和具体的日志方案直接耦合。类似于JDBC 的api 接口,具体的的JDBC driver 实现由各数据库提供商实现。通过统一接口解耦,不过其内部也实现了一些简单日志方案。
Log4j
Logging for Java,经典的一种日志解决方案。内部把日志系统抽象封装成Logger 、appender 、pattern 等实现。我们可以通过配置文件轻松的实现日志系统的管理和多样化配置。
slf4j
全称为Simple Logging Facade for Java。 是对不同日志框架提供的一个门面封装。可以在部署的时候不修改任何配置即可接入一种日志实现方案。和commons-loging 类似。个人感觉设从计上更好一些,没有commons 那么多潜规则。同时有两个额外特点:①能支持多个参数,并通过{}占位符进行替换,避免老写logger.isXXXEnabled这种无奈的判断,带来性能提升见;②OSGI机制更好兼容支持。
logback
作为一个通用可靠、快速灵活的日志框架,将作为Log4j 的替代和slf4j 组成新的日志系统的完整实现。具有极佳的性能,在关键路径上执行速度是log4j 的10 倍,且内存消耗更少。
Log4j2
Log4j2是Log4j的升级版,与之前的版本Log4j 1.x相比、有重大的改进,在修正了Logback固有的架构问题的同时,改进了许多Logback所具有的功能。
可以这么理解,slf4j和commons-logging是一种抽象接口,Log4j、Log4j2和logback是它们的实现,在实际使用中,一般选择slf4j+Log4j2或者slf4j+logback。
二、slf4j
为什么要使用slf4j
我们为什么要使用slf4j,举个例子:
我们自己的系统中使用了logback这个日志系统
我们的系统使用了A.jar,A.jar中使用的日志系统为log4j
我们的系统又使用了B.jar,B.jar中使用的日志系统为slf4j-simple
这样,我们的系统就不得不同时支持并维护logback、log4j、slf4j-simple三种日志框架,非常不便。
解决这个问题的方式就是引入一个适配层,由适配层决定使用哪一种日志系统,而调用端只需要做的事情就是打印日志而不需要关心如何打印日志,slf4j或者commons-logging就是这种适配层。
从上面的描述,我们必须清楚地知道一点:slf4j只是一个日志标准,并不是日志系统的具体实现。理解这句话非常重要,slf4j只做两件事情:
- 提供日志接口
- 提供获取具体日志对象的方法
slf4j-simple、logback都是slf4j的具体实现,log4j并不直接实现slf4j,但是有专门的一层桥接slf4j-log4j12来实现slf4j。
slf4j日志级别
- trace
- debug
- info
- warn
- error
slf4j + logback
依赖
Spring 环境需要slf4j以及它的实现(slf4j-api + logback)和lombok依赖
Spring Boot 环境默认加入了slf4j-api和logback的依赖,所以只需要添加lombok的依赖即可
IDEA需要安装lombok插件
pom引入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
配置logback
logback在启动时,根据以下步骤寻找配置文件:①在classpath中寻找logback-test.xml文件→②如果找不到logback-test.xml,则在 classpath中寻找logback.groovy文件→③如果找不到 logback.groovy,则在classpath中寻找logback.xml文件
如果上述的文件都找不到,则logback会使用JDK的SPI机制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator中的 logback 配置实现类,这个实现类必须实现Configuration接口,使用它的实现来进行配置
如果上述操作都不成功,logback 就会使用它自带的 BasicConfigurator 来配置,并将日志输出到console。
这里采用xml格式的配置文件:在resources目录下新建logback.xml文件,logback.xml文件的具体配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 -->
<property name="LOG_HOME" value="logs"/>
<property name="COLOR_PATTERN"
value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta( %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''})- %gray(%msg%xEx%n)"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 控制台输出 -->
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${LOG_HOME}/log_%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
</appender>
<!-- 按照每天生成日志文件 -->
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${LOG_HOME}/log_debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${LOG_HOME}/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${LOG_HOME}/log_info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${LOG_HOME}/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${LOG_HOME}/log_warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${LOG_HOME}/log_error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>2</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 生成html格式日志开始 -->
<!--<appender name="HTML" class="ch.qos.logback.core.FileAppender">-->
<!--<!– 过滤器,只记录WARN级别的日志 –>-->
<!--<!– <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level>-->
<!--<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> –>-->
<!--<encoder-->
<!--class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!--<layout class="ch.qos.logback.classic.html.HTMLLayout">-->
<!--<pattern>%p%d%msg%M%F{32}%L</pattern>-->
<!--</layout>-->
<!--</encoder>-->
<!--<file>${LOG_HOME}/error-log.html</file>-->
<!--</appender>-->
<!-- 生成html格式日志结束 -->
<!-- 每天生成一个html格式的日志开始 -->
<!--<appender name="FILE_HTML"-->
<!--class="ch.qos.logback.core.rolling.RollingFileAppender">-->
<!--<rollingPolicy-->
<!--class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">-->
<!--<!–日志文件输出的文件名 –>-->
<!--<FileNamePattern>${LOG_HOME}/insight-product.%d{yyyy-MM-dd}.html-->
<!--</FileNamePattern>-->
<!--<!–日志文件保留天数 –>-->
<!--<MaxHistory>15</MaxHistory>-->
<!--</rollingPolicy>-->
<!--<encoder-->
<!--class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!--<layout class="ch.qos.logback.classic.html.HTMLLayout">-->
<!--<pattern>%p%d%msg%M%F{32}%L</pattern>-->
<!--</layout>-->
<!--</encoder>-->
<!--<!–日志文件最大的大小 –>-->
<!--<triggeringPolicy-->
<!--class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
<!--<MaxFileSize>10MB</MaxFileSize>-->
<!--</triggeringPolicy>-->
<!--</appender>-->
<!-- 每天生成一个html格式的日志结束 -->
<!--myibatis log configure -->
<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 level="INFO">
<appender-ref ref="STDOUT"/>
<!--<appender-ref ref="FILE"/>-->
<appender-ref ref="ERROR_FILE"/>
<!--<appender-ref ref="WARN_FILE"/>-->
<appender-ref ref="INFO_FILE"/>
<!--<appender-ref ref="DEBUG_FILE"/>-->
<!--<appender-ref ref="HTML" />-->
<!--<appender-ref ref="FILE_HTML" />-->
</root>
</configuration>
使用
package com.example.springbootdemo.test;
import lombok.extern.slf4j.Slf4j;
/**
* Slf4jTest
*
* @author: wcx
* @date: 2022年06月16日 16:56
*/
@Slf4j
public class Slf4jTest {
public static void main(String[] args) {
log.info("Slf4jTest");
log.info("Slf4jTest:{}","占位符test");
}
}