开头
log4j2跟之前版本的区别就不发了,那玩意上网上搜有的是介绍的
这个文章主要是为了那些初学者上网上不好配搞得,直接扒就能用,网上其他文章不是给你讲概念,就是给你配置没发全发一半,有严谨性但是不通俗易懂。
先看下效果图
我这里有两个log,一个是info级别,一个是error级别
在我的磁盘里会生成两种级别的日志文件,这个文件里就是单独一种级别的,方便以后为了看有哪些error,还得去log里搜。
pom.xml
maven引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--全局排除spring-boot-starter-logging内的所有依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
log4j2.xml
在resource下建立文件 ,直接粘贴
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!-- status log4j2内部日志级别 -->
<!-- monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 -->
<configuration monitorInterval="5">
<!-- 全局参数 -->
<Properties>
<Property name="pattern">%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %c{1}:%L -%m%n</Property>
<Property name="displayName">CeipageServer</Property>
<!-- 定义日志存储的路径 -->
<property name="FILE_PATH">E://Ceinet</property>
<!--项目名称-->
<property name="FILE_NAME">CeipageServer</property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT" follow="true">
<!--输出日志的格式-->
<PatternLayout pattern="${pattern}"/>
<!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<!-- 文件 每次运行程序会自动清空,由append属性决定, 临时测试用 -->
<File name="error" fileName="${FILE_NAME}_ERROR.log" append="true">
<!-- 指定error 级别的日志 -->
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="${pattern}"/>
</File>
<!-- 滚动文件 -->
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/${FILE_NAME}_INFO.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${pattern}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<!-- 按大小划分 -->
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
<!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/${FILE_NAME}_ERROR.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${pattern}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<!-- 按大小划分 -->
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="console"></AppenderRef>
<AppenderRef ref="error"></AppenderRef>
<AppenderRef ref="RollingFileInfo"></AppenderRef>
<AppenderRef ref="RollingFileError"></AppenderRef>
</Root>
</Loggers>
</configuration>
这里面的配置我拷了好几个文章然后改吧改吧整合的
这里注意几个地方,根据自己情况修改
- FILE_PATH,这个是日志输出的磁盘路径,这个跟据你以后部署windows还是linux,路径需要搞对
- FILE_NAME,这个名不说了,有注释的,就是生成的文件名,肯定换成自己的啊
- <Appenders>里面的console,有个level等级,看你要控制台输出的日志等级了,等级这玩意会生成大于你当前级别的全部级别(OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL),举个例子你写的是error,那么输出的就是off和fatal和error,一般情况都写info
- <File>测试用的,打包后用不上了,这个会在你项目目录里生成日志文件
- <RollingFile>这个是主要的,部署后会根据这里面的配置生成log文件,就是我截图那个效果图,一个级别写一个,我这里面只写了INFO和ERROR级别的,需要其他级别的复制一个然后改吧改吧就行
- <Loggers> 里面的ref对应上面配置的name,得对应上哦要不然不输出,尤其对应RollingFile的name
LoggerUtil.java
这个是我们自己写的log工具类,发现2代里调用log改成LogManager了。 这里面我们做了调用类的处理,可以不用像以前似的每个类里都得getLogger(XXXX.class)了
这个不一定非得用我们的,自己有封装的更好
package com.cei.utils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import sun.reflect.Reflection;
import java.util.Date;
public class LoggerUtil {
private static boolean isLog = true;
private static Logger logger = null;
public static void setLogger(boolean isLog) {
LoggerUtil.isLog = isLog;
}
public static void setLog(Logger logger) {
LoggerUtil.logger = logger;
}
public static void setLogger(Logger logger) {
LoggerUtil.logger = logger;
}
public static void debug(Object msg) {
if (isLog) {
if (logger == null) {
StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
if (stackTraceElement.length > 3) {
logger = LogManager.getLogger(stackTraceElement[2].getClassName());
logger.debug("调用者类名" + stackTraceElement[2].getClassName());
} else {
logger = LogManager.getLogger(Reflection.getCallerClass(2).getName());
logger.debug("调用者类名" + Reflection.getCallerClass(2).getName());
}
}
logger.debug(new Date() + " " + msg);
}
}
public static void info(Object msg) {
if (isLog) {
if (logger == null) {
StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
if (stackTraceElement.length > 3) {
logger = LogManager.getLogger(stackTraceElement[2].getClassName());
logger.debug("调用者类名" + stackTraceElement[2].getClassName());
} else {
logger = LogManager.getLogger(Reflection.getCallerClass(2).getName());
logger.debug("调用者类名" + Reflection.getCallerClass(2).getName());
}
}
logger.info(new Date() + " " + msg);
}
}
public static void warn(Object msg) {
if (isLog) {
if (logger == null) {
StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
if (stackTraceElement.length > 3) {
logger = LogManager.getLogger(stackTraceElement[2].getClassName());
logger.debug("调用者类名" + stackTraceElement[2].getClassName());
} else {
logger = LogManager.getLogger(Reflection.getCallerClass(2).getName());
logger.debug("调用者类名" + Reflection.getCallerClass(2).getName());
}
}
logger.warn(new Date() + " " + msg);
}
}
public static void error(Object msg) {
if (isLog) {
if (logger == null) {
StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
if (stackTraceElement.length > 3) {
logger = LogManager.getLogger(stackTraceElement[2].getClassName());
logger.debug("调用者类名" + stackTraceElement[2].getClassName());
} else {
logger = LogManager.getLogger(Reflection.getCallerClass(2).getName());
logger.debug("调用者类名" + Reflection.getCallerClass(2).getName());
}
}
logger.error(new Date() + " " + msg);
}
}
public static void fatal(Object msg) {
if (isLog) {
if (logger == null) {
StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
if (stackTraceElement.length > 3) {
logger = LogManager.getLogger(stackTraceElement[2].getClassName());
logger.debug("调用者类名" + stackTraceElement[2].getClassName());
} else {
logger = LogManager.getLogger(Reflection.getCallerClass(2).getName());
logger.debug("调用者类名" + Reflection.getCallerClass(2).getName());
}
}
logger.fatal(new Date() + " " + msg);
}
}
}
还有就是我们是类似抓异常那种线程抓类名,而不是用的这个
这个有过时的注解了,不是不能用,但是怕有问题就没用
调用
调用就简单了,上面都配好后 ,随便调