前言
上一篇:老树开新花:在MyEclipse环境中配置和使用SpringBoot——连接数据库
这一篇的内容相较之前而言更为简单了。今天我们来聊一聊怎样在SpringBoot架构体系之中继续使用很多老程序员已经习惯了的Log4j。
依赖
我们仍然从依赖开始。想要使用Log4j,毫无疑问必定先要添加对它的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
但是这里有一个陷阱。如果单单引入Log4j的依赖,是无法正常使用它的。因为SpringBoot默认使用的日志系统是LogBack。想要使用Log4j,必须先排除SpringBoot对LogBack的使用。因此我们需要在spring-boot-starter-web的依赖中排除它:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.1.RELEASE</version>
<exclusions>
<!-- 排除自带的spring-boot-starter-logging(基于logback),以便使用log4j2 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<!-- 移除嵌入式tomcat插件 ,便于独立打包至外部tomcat -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
除此以外,也需要在依赖spring-boot-starter中排除相关的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
Log4j配置文件
我们需要在resource folder中添加一个xml文件,把它固定命名为“log4j2-spring.xml”,这样一来,SpringBoot就会自动装载这个配置文件,并为Log4j完成初始化。
在这个文件中,我们编辑以下的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!-- status="OFF",可以去掉,它的含义为是否记录log4j2本身的event信息,默认是OFF -->
<configuration status="OFF">
<!-- 定义下面的引用名 -->
<!--
自定义格式:
%t:线程名称
%p:日志级别
%c:日志消息所在类名
%m:消息内容
%M:输出执行方法
%d:发生时间,%d{yyyy-MM-dd HH:mm:ss,SSS},输出类似:2018-10-18 22:10:28,921
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%L:代码中的行数
%n:换行
-->
<Properties>
<property name="log_pattern">%d{yyyy-MM-dd HH:mm:ss z} %-5p %c{36} %L %M - %m%x%n</property>
<property name="file_path">/home/freezingxu/logs</property>
<property name="file_name">freezing_spring_boot</property>
<property name="every_file_size">10M</property><!-- 日志切割的最小单位 -->
<property name="output_log_level">debug</property><!-- 日志输出级别 -->
</Properties>
<!--先定义所有的appender-->
<!-- 日志级别
trace:追踪,就是程序推进一下,可以写个trace输出
debug:调试,一般作为最低级别,trace基本不用。
info:输出重要的信息,使用较多
warn:警告,有些信息不是错误信息,但也要给一些提示。
error:错误信息。用的也很多。
fatal:致命错误。级别较高.
-->
<appenders>
<!--Appenders节点,常见的有三种子节点:Console、RollingFile、File.-->
<!-- Console
name :给loggers调用
target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.
-->
<Console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"></ThresholdFilter>
<!--输出日志的格式-->
<PatternLayout pattern="${log_pattern}"></PatternLayout>
</Console>
<!--File
fileName:指定输出日志的目的文件带全路径的文件名.
append:决定是否添加还是重新建文件会打印出所有信息,false这个log每次运行程序会自动清空,
-->
<File name="logFile" fileName="${file_path}/${file_name}_info.log" append="true" >
<PatternLayout pattern="${log_pattern}"></PatternLayout>
</File>
<!-- 打印root中指定的level级别以上的日志到文件 -->
<RollingFile name="RollingFileAll" fileName="${file_path}/${file_name}_all.log" filePattern="${file_path}/${file_name}_%d{yyyy-MM-dd}_all.log.zip">
<PatternLayout pattern="${log_pattern}"/>
<Policies>
<!-- jvm重启就进行一次rollover-->
<OnStartupTriggeringPolicy />
<!-- 文件大小达到10mb进行一次rollover -->
<SizeBasedTriggeringPolicy size="${every_file_size}" />
<!-- TimeBasedTriggeringPolicy是最多用到的Policy,interval默认值是1,根据filePattern中日期的最小单位,例如
在该配置里是mm(分钟),设置interval="2"则每隔两分钟将发生一次rollover,按当前配置,具体表现就是隔两分钟得到一个log.zip。
modulate就是让第一次rollover发生在区间边界上(即便还没到interval的时长),按照当前配置,首次rollover会发生在比如8点50分0秒,
这样之后的rollover就是8点52分0秒、8点54分0秒..
这样做的好处在于rollover的时机就变得很有规律很好预测,生成的文件还很整齐(假设时间最小单位为天,interval="1",那么就变成稳定每天0点自动rollover了。。)。
还有个属性叫maxRandomDelay,防止很多应用在同一时间一起rollover的,暂时不理它。
-->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<!-- 打印INFO级别的日志到文件 -->
<RollingFile name="RollingFileInfo" fileName="${file_path}/${file_name}_info.log" filePattern="${file_path}/${file_name}_%d{yyyy-MM-dd}_info.log.zip">
<PatternLayout pattern="${log_pattern}"/>
<!-- 匹配INFO级别 -->
<Filters>
<ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Policies>
<!-- jvm重启就进行一次rollover-->
<OnStartupTriggeringPolicy />
<!-- 文件大小达到10mb进行一次rollover -->
<SizeBasedTriggeringPolicy size="${every_file_size}" />
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<!-- 打印WARN级别的日志到文件 -->
<RollingFile name="RollingFileWarn" fileName="${file_path}/${file_name}-warn.log" filePattern="${file_path}/${file_name}_%d{yyyy-MM-dd}_warn.log.zip">
<PatternLayout pattern="${log_pattern}"/>
<!-- 匹配WARN级别 -->
<Filters>
<ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Policies>
<!-- jvm重启就进行一次rollover-->
<OnStartupTriggeringPolicy />
<!-- 文件大小达到10mb进行一次rollover -->
<SizeBasedTriggeringPolicy size="${every_file_size}" />
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<!-- 打印ERROR级别的日志到文件 -->
<RollingFile name="RollingFileError" fileName="${file_path}/${file_name}-error.log" filePattern="${file_path}/${file_name}_%d{yyyy-MM-dd}_error.log.zip">
<PatternLayout pattern="${log_pattern}"/>
<!-- 匹配ERROR级别 -->
<Filters>
<ThresholdFilter level="fatal" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<Policies>
<!-- jvm重启就进行一次rollover-->
<OnStartupTriggeringPolicy />
<!-- 文件大小达到10mb进行一次rollover -->
<SizeBasedTriggeringPolicy size="${every_file_size}" />
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
</appenders>
<!--定义logger
只有定义了logger并引入的appender,appender才会生效
常见的有两种:Root和Logger.
Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender.
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.
AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,
那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。
-->
<loggers>
<!--log4j2 自带过滤日志-->
<logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
<logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<logger name="org.crsh.plugin" level="warn" />
<logger name="org.crsh.ssh" level="warn"/>
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
<logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
<logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
<logger name="org.thymeleaf" level="warn"/>
<!-- 设置对打印sql语句的支持 -->
<logger name="java.sql" level="debug" additivity="false">
<appender-ref ref="Console"/>
<appender-ref ref="logFile"/>
<appender-ref ref="RollingFileInfo"/>
</logger>
<!--建立一个默认的root的logger -->
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="logFile"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</loggers>
</configuration>
Java代码
好了,到这里,就可以直接在代码中使用Log4j了。使用的方式还是跟过去一模一样:
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
//...
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(HelloController.class.getName());
//...
logger.info("hello logger!");