还不知道项目中怎么写日志?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进行配置即可


(七)总结


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

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
7月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
1748 1
|
7月前
|
Java 微服务 Spring
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——使用Logger在项目中打印日志
本文介绍了如何在项目中使用Logger打印日志。通过SLF4J和Logback,可设置不同日志级别(如DEBUG、INFO、WARN、ERROR)并支持占位符输出动态信息。示例代码展示了日志在控制器中的应用,说明了日志配置对问题排查的重要性。附课程源码下载链接供实践参考。
827 0
|
7月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
663 0
|
7月前
|
Java API 开发者
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——slf4j 介绍
在软件开发中,`System.out.println()`常被用于打印信息,但大量使用会增加资源消耗。实际项目推荐使用slf4j结合logback输出日志,效率更高。Slf4j(Simple Logging Facade for Java)是一个日志门面,允许开发者通过统一方式记录日志,无需关心具体日志系统。它支持灵活切换日志实现(如log4j或logback),且具备简洁占位符和日志级别判断等优势。阿里巴巴《Java开发手册》强制要求使用slf4j,以保证日志处理方式的统一性和维护性。使用时只需通过`LoggerFactory`创建日志实例即可。
507 0
|
5月前
|
监控 容灾 算法
阿里云 SLS 多云日志接入最佳实践:链路、成本与高可用性优化
本文探讨了如何高效、经济且可靠地将海外应用与基础设施日志统一采集至阿里云日志服务(SLS),解决全球化业务扩展中的关键挑战。重点介绍了高性能日志采集Agent(iLogtail/LoongCollector)在海外场景的应用,推荐使用LoongCollector以获得更优的稳定性和网络容错能力。同时分析了多种网络接入方案,包括公网直连、全球加速优化、阿里云内网及专线/CEN/VPN接入等,并提供了成本优化策略和多目标发送配置指导,帮助企业构建稳定、低成本、高可用的全球日志系统。
654 54
|
7月前
|
监控 Java 应用服务中间件
Tomcat log日志解析
理解和解析Tomcat日志文件对于诊断和解决Web应用中的问题至关重要。通过分析 `catalina.out`、`localhost.log`、`localhost_access_log.*.txt`、`manager.log`和 `host-manager.log`等日志文件,可以快速定位和解决问题,确保Tomcat服务器的稳定运行。掌握这些日志解析技巧,可以显著提高运维和开发效率。
606 13
|
7月前
|
缓存 Java 编译器
|
8月前
|
存储 缓存 关系型数据库
图解MySQL【日志】——Redo Log
Redo Log(重做日志)是数据库中用于记录数据页修改的物理日志,确保事务的持久性和一致性。其主要作用包括崩溃恢复、提高性能和保证事务一致性。Redo Log 通过先写日志的方式,在内存中缓存修改操作,并在适当时候刷入磁盘,减少随机写入带来的性能损耗。WAL(Write-Ahead Logging)技术的核心思想是先将修改操作记录到日志文件中,再择机写入磁盘,从而实现高效且安全的数据持久化。Redo Log 的持久化过程涉及 Redo Log Buffer 和不同刷盘时机的控制参数(如 `innodb_flush_log_at_trx_commit`),以平衡性能与数据安全性。
296 5
图解MySQL【日志】——Redo Log
|
7月前
|
SQL 存储 关系型数据库
简单聊聊MySQL的三大日志(Redo Log、Binlog和Undo Log)各有什么区别
在MySQL数据库管理中,理解Redo Log(重做日志)、Binlog(二进制日志)和Undo Log(回滚日志)至关重要。Redo Log确保数据持久性和崩溃恢复;Binlog用于主从复制和数据恢复,记录逻辑操作;Undo Log支持事务的原子性和隔离性,实现回滚与MVCC。三者协同工作,保障事务ACID特性。文章还详细解析了日志写入流程及可能的异常情况,帮助深入理解数据库日志机制。
888 0

热门文章

最新文章