还不知道项目中怎么写日志?slf4j+log4j帮你搞定!

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 之前讲到了排查问题最重要的两种方法:查日志、debug。断点调试在上一期讲了,这期就讲讲日志。本文将从Log4j入手,分别介绍slf4j、Log4j2以及SpringBoot中的日志使用。

网络异常,图片无法展示
|


听说微信搜索《Java鱼仔》会变更强哦!


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看哦


前言


之前讲到了排查问题最重要的两种方法:查日志、debug。断点调试在上一期讲了,这期就讲讲日志。本文将从Log4j入手,分别介绍slf4j、Log4j2以及SpringBoot中的日志使用。


(一)Log4j


Log4j主要由Loggers(日志记录器)、Appenders(输出端)和Layout(日志格式化器)组成,其中Loggers控制日志输出的级别与日志是否输出;Appenders指定日志的输出方式(输出到控制台或者文件);Layout控制日志信息的输出格式。


1.1 引入依赖


首先引入Log4j的相关依赖:


<!--log4j--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>

1.2 使用


在不自定义配置文件的情况下,可以通过BasicConfigurator.configure();设置一个基本的配置,Log4j的日志共有六种级别,主要使用的是中间的四种:

//如果没有自定义配置信息的话加上下面的代码BasicConfigurator.configure();
Loggerlogger=Logger.getLogger(Log4jTest.class);
//logger日志级别logger.fatal("fatal");  //严重错误,一般会造成系统崩溃并终止运行logger.error("error");  //错误信息,不会影响系统运行logger.warn("warn");   //警告信息,可能会发生问题logger.info("info");    //运行信息,比如数据库连接、网络连接等logger.debug("debug");  //调试信息,一般用在开发过程中打印调试信息logger.trace("trace");  //追踪信息,记录程序所有的流程信息


1.3 自定义配置信息


通过分析LoggerManager的源码可以发现,Log4j会去查找log4j.xml和log4j.properties文件中的配置信息。因此我们自定义配置文件时也需要创建这两个文件中的其中一个,现在广泛使用log4j.properties


网络异常,图片无法展示
|


接下来简单配置一下:


Logger控制日志输出的级别与日志是否输出,通过rootLogger可以设置输出的最低级别。


appender指定日志的输出方式,这里选择输出到控制台


layout控制日志信息的输出格式,这里使用简单格式


log4j.rootLogger=info,consolelog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.layout=org.apache.log4j.SimpleLayout

(二)Log4j日志配置文件详解


接下来详细介绍Log4j配置文件:


#指定RootLogger顶级父元素默认的配置信息,指定日志级别=info,使用的append为console(自己命名)log4j.rootLogger=info,console#指定控制台日志输出的appender,这里名字要和上面填入的一致consolelog4j.appender.console=org.apache.log4j.ConsoleAppender#指定消息格式layoutlog4j.appender.console.layout=org.apache.log4j.SimpleLayout

2.1 常用的Layout


HTMLLayout:格式化日志输出为HTML表格样式


SimpleLayout:简单的日志输出格式


PatternLayout:可以根据自定义格式输出日志,如果没有指定转换格式,就是采用默认的格式


重点介绍最常用的PatternLayout


使用方式:



log4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.conversionPattern= [%p]%r%l%d{yyyy-MM-ddHH:mm:ss.SSS} %m%n

conversionPattern是格式,上面的这个格式化可以直接拿过去用,其他参数配置如下:

%m输出代码中指定的日志信息%p输出优先级%n换行符%r输出应用启动到该log信息耗费的毫秒数%c输出打印语句所属的类的全名%t输出产生该日志的线程全名%d输出服务器当前时间,默认ISO8601,也可以指定格式如%d{yyyy-MM-ddHH:mm:ss.SSS}
%l输出日志时间发生的位置,包括类名、线程及在代码钟的行数%F输出日志消息产生时所在的文件名称%L输出代码中的行号%%输出一个%符号

2.2 常用的appender


ConsoleAppender:控制台输出


FileAppender:文件中输出


JDBCAppender:数据库中输出


2.2.1 FileAppender


介绍FileAppender文件输出的一些自定义配置


#将file也配置到rootLogger中log4j.rootLogger=info,console,file#省略console的配置#指定appender以文件形式输出log4j.appender.file=org.apache.log4j.FileAppender#指定文件的名称和路径log4j.appender.file.file=/logs/log4j.log#指定日志文件的字符集log4j.appender.file.encoding=UTF-8#日志格式log4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.conversionPattern= [%p]%r%l%d{yyyy-MM-ddHH:mm:ss.SSS} %m%n

我们还可以根据业务的不同,使用RollingFIleAppender或者DailyRollingFileAppender RollingFIleAppender按照文件大小拆分,设置文件内容最大值以及文件数量,如果都超过则覆盖之前的。

#按照文件大小拆分#指定appender以文件形式输出log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender#指定文件的名称和路径log4j.appender.rollingFile.file=/logs/log4j.log#指定日志文件的字符集log4j.appender.rollingFile.encoding=UTF-8#日志格式log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayoutlog4j.appender.rollingFile.layout.conversionPattern= [%p]%r%l%d{yyyy-MM-ddHH:mm:ss.SSS} %m%n#指定日志文件内容的大小log4j.appender.rollingFile.maxFileSize=1MB#指定日志文件的数量log4j.appender.rollingFile.maxBackupIndex=10

DailyRollingFileAppender按照文件日期拆分,根据设定的日期规则生成日志文件。

#按照时间规则拆分#指定appender以文件形式输出log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender#指定文件的名称和路径log4j.appender.dailyFile.file=/logs/log4j.log#指定日志文件的字符集log4j.appender.dailyFile.encoding=UTF-8#日志格式log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayoutlog4j.appender.dailyFile.layout.conversionPattern= [%p]%r%l%d{yyyy-MM-ddHH:mm:ss.SSS} %m%n#按照日期拆分规则log4j.appender.dailyFile.datePattern='.'yyyy-MM-dd

2.2.2 JDBCAppender


jdbcAppender就是将日志数据通过sql语句写入数据库中,因此需要提前建好一张表,再通过insert语句插入数据。

#JDBCAppenderlog4j.appender.dbLog=org.apache.log4j.jdbc.JDBCAppenderlog4j.appender.dbLog.layout=org.apache.log4j.PatternLayoutlog4j.appender.dbLog.Driver=com.mysql.jdbc.Driverlog4j.appender.dbLog.URL=jdbc:mysql://localhost:3306/testlog4j.appender.dbLog.User=rootlog4j.appender.dbLog.Password=123456log4j.appender.dbLog.Sql=INSERTINTOlog(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('logDemo','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')

(三)SLF4J


简单日志门面(Simple Logging Facade For Java)主要是为了给Java日志提供一套标准的API框架,具体的实现交由其他日志框架实现,比如Log4j。一般的SpringBoot项目会将slf4j作为门面,配合Log4j使用。接下来介绍slf4j绑定log4j的使用方式。


需要注意一点:slf4j同时只能有一个绑定日志框架,因此依赖SpringBoot的一些启动依赖可能会和下面的依赖冲突。学习时只需要下面几个依赖即可。


3.1 引入依赖:


<!--slf4j--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.26</version></dependency><!--slf4j绑定log4j--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.12</version></dependency><!--log4j--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>

3.2 配置文件


将之前的log4j.properties配置文件放到resource目录下。


3.3 写代码


importorg.junit.Test;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
publicclassLogTest {
privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(LogTest.class);
@Testpublicvoidtest(){
//日志级别LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
//使用占位符输出Stringname="java鱼仔";
Stringage="24";
LOGGER.info("name:{},age:{}",name,age);
    }
}

3.3 slf4j桥接器


如果一个项目的日志框架原来用的是log4j,现在要改成logback,对slf4j来说只需要把log4j的依赖去除,然后加上logback的依赖即可,但是这时候会出现一个问题,以前用log4j写的代码就会报错。


网络异常,图片无法展示
|


slf4j提供了一种叫做桥接器的工具,只需要引入对应的依赖,就可以兼容旧的日志框架,并且以前代码中的Logger执行时自动更换成新的日志框架:



<dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId><version>1.7.25</version></dependency>


注意,桥接器依赖不能和正式依赖一起出现!


(四)Log4j2


Log4j的升级版本,主要有下面的提升:


1、异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。


2、性能提升,logj2相较于log4j和logback都具有很明显的性能提升。


3、自动重载配置,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。


4、无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的GC。


log4j2本身既是日志门面,也是日志框架,不过现在Slf4j+Log4j2依然是热门的选型,下面就通过这种日志选型进行介绍。


4.1 引入依赖


<!--slf4j--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.26</version></dependency><!--使用log4j2进行绑定--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.9.1</version></dependency><!--log4j2日志实现--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.10.0</version></dependency>

4.2 配置


log4j2在启动时会去resource路径下选择log4j2.xml的配置文件,这里列出一个xml模板,可以直接拿过去用


<?xmlversion="1.0" encoding="UTF-8"?><!--status="WARN" 日志框架本身的输出日志级别monitorInterval="5" 自动加载配置文件的间隔时间不低于5秒--><Configurationstatus="WARN"monitorInterval="5"><!--全局参数,使用时可以通过${name}的方式使用--><properties><propertyname="pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %l %c{36} - %m%n</property><propertyname="logDir">/logs</property></properties><!--Logger定义,使用哪些Logger--><Loggers><Rootlevel="INFO"><AppenderRefref="console"/><AppenderRefref="rolling_file"/></Root></Loggers><Appenders><!-- 定义输出到控制台 --><Consolename="console"target="SYSTEM_OUT"follow="true"><!--控制台只输出level及以上级别的信息--><ThresholdFilterlevel="INFO"onMatch="ACCEPT"onMismatch="DENY"/><PatternLayout><Pattern>${pattern}</Pattern></PatternLayout></Console><!-- 按照一定规则拆分的日志文件的appender --><RollingFilename="rolling_file"fileName="${logDir}/rolling-file.log"filePattern="${logDir}/rolling-file_%d{yyyy-MM-dd}.log"><ThresholdFilterlevel="INFO"onMatch="ACCEPT"onMismatch="DENY"/><PatternLayout><Pattern>${pattern}</Pattern></PatternLayout><Policies><!--按照时间节点进行拆分--><TimeBasedTriggeringPolicyinterval="1"/></Policies><!-- 日志保留策略,配置只保留七天 --><DefaultRolloverStrategy><DeletebasePath="${logDir}/"maxDepth="1"><IfFileNameglob="rolling-file_*.log"/><IfLastModifiedage="7d"/></Delete></DefaultRolloverStrategy></RollingFile></Appenders></Configuration>

4.3 代码的使用


在使用时其实就是用slf4j这个日志门面,只不过底层日志框架变成了log4j2

importorg.junit.Test;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
publicclassLogTest {
privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(LogTest.class);
@Testpublicvoidtest(){
//日志级别LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
//使用占位符输出Stringname="java鱼仔";
Stringage="24";
LOGGER.info("name:{},age:{}",name,age);
    }
}

(五)log4j2异步日志


之前将的所有日志框架都是通过同步的方式来打日志,log4j2提供了异步日志的功能,配置异步日志后,logger.info等代码生成的日志事件会被放到一个异步线程中去处理,从而不会影响系统的运行速度。下面介绍log4j2异步日志的实现方式:


5.1 引入依赖


<!--异步日志--><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.3.4</version></dependency>

5.2 局部异步处理


局部异步处理有两种方式,首先第一种是在Appender中添加异步处理:


主要有两步,第一步是在Appender中引入Async标签,第二步是在Loggers中引入异步标签

<Appenders><!-- 定义输出到控制台 --><Consolename="console"target="SYSTEM_OUT"follow="true"><!-- 内部的配置请看上面 --></Console><!-- 按照一定规则拆分的日志文件的appender --><RollingFilename="rolling_file"fileName="${logDir}/rolling-file.log"filePattern="${logDir}/rolling-file_%d{yyyy-MM-dd}.log"><!-- 内部的配置请看上面 --></RollingFile><!--把rolling_file改为异步实现--><Asyncname="Async"><AppenderRefref="rolling_file"/></Async></Appenders><Loggers><Rootlevel="INFO"><AppenderRefref="console"/><!--引入异步的appender--><AppenderRefref="Async"/></Root></Loggers>

第二种方式是在Loggers中添加异步日志定义:

<Loggers><!--name表示自定义的异步Logger名称level表示最低级别includeLocation="false"  关闭日志记录的行号信息additivity="false"  不继承rootlogger对象--><AsyncLoggername="com.javayz"level="trace"includeLocation="false"additivity="false"><AppenderRefref="rolling_file"/></AsyncLogger><Rootlevel="INFO"><AppenderRefref="console"/><AppenderRefref="rolling_file"/></Root></Loggers>

5.3 全局异步


在resource文件下新建一个配置,命名为log4j2.component.properties,在这个文件中加一句:

Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

(六)在SpringBoot中使用Logger


使用SpringBoot的日志需要引入一个启动依赖,这个依赖是包含在web启动依赖中的

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency>

SpringBoot中默认使用slf4j作为日志门面,使用logback作为日志的实现。

importorg.junit.jupiter.api.Test;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.boot.test.context.SpringBootTest;
@SpringBootTestclassSpringlogApplicationTests {
publicstaticfinalLoggerLOGGER=LoggerFactory.getLogger(SpringlogApplicationTests.class);
@TestvoidcontextLoads() {
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info"); //默认到info级别LOGGER.debug("debug");
LOGGER.trace("trace");
    }
}

通过application的简单配置即可使用:

#指定日志级别logging.level.com.javayz=trace#指定控制台输出的格式logging.pattern.console=[%-5level] %d{yyyy-MM-ddHH:mm:ss} %c [%thread]   %msg%n#指定日志文件存放路径,默认生成spring.loglogging.file.path=/logs/springboot#指定文件中输出的格式logging.pattern.file=[%-5level] %d{yyyy-MM-ddHH:mm:ss} %c [%thread]   %msg%n

如果觉得这些配置太简单,可以在resource目录下新建logback.xml(对应logback)

但是现在由于log4j2的性能要高于logback,一般项目中还是会选择log4j2,这时候就需要把默认的logback改成log4j2。修改方式:移除spring-boot-starter-logging依赖,引入log4j2依赖


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><!--排除logging--><exclusion><artifactId>spring-boot-starter-logging</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入log4j2--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency>


然后在resource目录下新建log4j2.xml,按log4j2进行配置即可


(七)总结


日志的配置和使用很简单,但是确是找问题的好帮手,我是鱼仔,我们下期再见。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
271 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
299 3
|
1月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
45 1
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1684 14
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
40 0
|
2月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
257 0
|
3月前
|
Java
日志框架log4j打印异常堆栈信息携带traceId,方便接口异常排查
日常项目运行日志,异常栈打印是不带traceId,导致排查问题查找异常栈很麻烦。
|
4月前
|
XML Java Maven
log4j 日志的简单使用
这篇文章介绍了Log4j日志框架的基本使用方法,包括在Maven项目中添加依赖、配置`log4j.properties`文件以及在代码中创建和使用Logger对象进行日志记录,但实际打印结果中日志级别没有颜色显示。
log4j 日志的简单使用
|
4月前
|
XML Java Maven
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
这篇文章是Spring5框架的入门到实战教程,介绍了Spring5的新功能——整合日志框架Log4j2,包括Spring5对日志框架的通用封装、如何在项目中引入Log4j2、编写Log4j2的XML配置文件,并通过测试类展示了如何使用Log4j2进行日志记录。
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
|
4月前
|
存储 消息中间件 监控
Java日志详解:日志级别,优先级、配置文件、常见日志管理系统ELK、日志收集分析
Java日志详解:日志级别,优先级、配置文件、常见日志管理系统、日志收集分析。日志级别从小到大的关系(优先级从低到高): ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF 低级别的会输出高级别的信息,高级别的不会输出低级别的信息