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

简介: 之前讲到了排查问题最重要的两种方法:查日志、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日志并进行多维度分析。
相关文章
|
21天前
|
Java
使用Java代码打印log日志
使用Java代码打印log日志
75 1
|
22天前
|
Linux Shell
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
77 1
|
26天前
|
SQL 关系型数据库 MySQL
MySQL数据库,可以使用二进制日志(binary log)进行时间点恢复
对于MySQL数据库,可以使用二进制日志(binary log)进行时间点恢复。二进制日志是MySQL中记录所有数据库更改操作的日志文件。要进行时间点恢复,您需要执行以下步骤: 1. 确保MySQL配置文件中启用了二进制日志功能。在配置文件(通常是my.cnf或my.ini)中找到以下行,并确保没有被注释掉: Copy code log_bin = /path/to/binary/log/file 2. 在需要进行恢复的时间点之前创建一个数据库备份。这将作为恢复的基准。 3. 找到您要恢复到的时间点的二进制日志文件和位置。可以通过执行以下命令来查看当前的二进制日志文件和位
|
1天前
|
Java
log4j异常日志过滤规则配置
log4j异常日志过滤规则配置
7 0
|
13天前
|
运维 安全 Ubuntu
`/var/log/syslog` 和 `/var/log/messages` 日志详解
`/var/log/syslog` 和 `/var/log/messages` 是Linux系统的日志文件,分别在Debian和Red Hat系发行版中记录系统事件和错误。它们包含时间戳、日志级别、PID及消息内容,由`rsyslog`等守护进程管理。常用命令如`tail`和`grep`用于查看和搜索日志。日志级别从低到高包括`debug`到`emerg`,表示不同严重程度的信息。注意保护日志文件的安全,防止未授权访问,并定期使用`logrotate`进行文件轮转以管理磁盘空间。
19 1
|
14天前
|
网络协议 应用服务中间件 Linux
centos7 Nginx Log日志统计分析 常用命令
centos7 Nginx Log日志统计分析 常用命令
27 2
|
14天前
|
Ubuntu Linux 网络安全
/var/log/auth.log日志详解
`/var/log/auth.log`是Linux(尤其是Debian系如Ubuntu)记录身份验证和授权事件的日志文件,包括登录尝试(成功或失败)、SSH活动、sudo使用和PAM模块的操作。登录失败、SSH连接、sudo命令及其它认证活动都会在此记录。查看此日志通常需root权限,可使用`tail`、`less`或`grep`命令。文件内容可能因发行版和配置而异。例如,`sudo tail /var/log/auth.log`显示最后几行,`sudo grep &quot;failed password&quot; /var/log/auth.log`搜索失败密码尝试。
56 8
|
27天前
|
监控 Java 测试技术
日志框架到底是Logback 还是 Log4j2
日志框架到底是Logback 还是 Log4j2
18 0
|
SQL 数据采集 监控
基于日志服务数据加工分析Java异常日志
采集并脱敏了整个5月份的项目异常日志,准备使用日志服务数据加工做数据清洗以及分析。本案例是基于使用阿里云相关产品(OSS,RDS,SLS等)的SDK展开自身业务。需要对异常日志做解析,将原始日志中时间、错误码、错误信息、状态码、产品信息、请求方法、出错行号提取出来。然后根据提取出来的不同产品信息做多目标分发处理。对清洗后的数据做异常日志数据分析。
712 0
基于日志服务数据加工分析Java异常日志
|
1月前
|
监控 Shell Linux
【Shell 命令集合 系统管理 】Linux 自动轮转(log rotation)日志文件 logrotate命令 使用指南
【Shell 命令集合 系统管理 】Linux 自动轮转(log rotation)日志文件 logrotate命令 使用指南
49 0