Java中日志框架种类繁多,我也是最近在学习mybatis过程中对日志的使用产生了困惑,所以这里个人做下总结,希望能帮助到和我有一样困惑的朋友,下面我们就开始吧!
Java中的第一个日志框架是apache提出来的log4j
,如下:
后来呢,sun公司认为自己作为java的开发主体,日志肯定是需要自己来给出方案的,为了打压log4j,于是在jdk4中制定了JULjava util logging
,在rt.jar
的java.util.logging包中,如下:
与此同时,又有一些其他的日志框架也被提了出来,比如simplelog,此时java日志体系如下图:
但是众多的毫无关系的日志框架,势必在我们的项目中造成混乱,比如项目中使用的是log4j,依赖的库A使用的是JUL,依赖的库B使用的是simplelog,这样一个项目中各种日志框架混杂,项目会越来越不好维护,越来越混乱,此时这个问题就亟需解决。这个时候,apache社区提出了commons-logging即JCL
的日志抽象来适配各种日志框架,此时java日志体系就变成下图:
之后呢,log4j的作者提出了一个对标JCL的日志抽象适配接口SLF4J
(simple logging facade for Java),不仅如此还直接开发一个基于SLF4J的日志框架实现logback
,与此同时呢,又继续维护并升级了log4j,形成了其升级版本log4j2
,此时Java日志体系变为下图红色框为本部分新介绍的
:
这个图也是目前java日志体系发展的现状了。
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
#使某个功能的日志单独输出到指定的日志文件
log4j.logger.saveUserLog=INFO,saveUserLog
#该配置就是让job的日志只输出到自己指定的日志文件中,表示Logger不会在父Logger的appender里输出,默认为true。
log4j.additivity.saveUserLog=false
log4j.appender.saveUserLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.saveUserLog.File=d:\\test\\testlog4j\\saveUserLog.log
log4j.appender.saveUserLog.DatePattern=yyyy-MM-dd
log4j.appender.saveUserLog.Append=true
log4j.appender.saveUserLog.layout=org.apache.log4j.PatternLayout
log4j.appender.saveUserLog.layout.ConversionPattern=%m%n
#log4j.appender.error.encoding=UTF-8
注意,在该配置中只配置了名称为saveUserLog
日志的配置。
public class TestLog4j {
public static void main(String[] args) {
// 使用默认的log4j.rootLogger=info,file,error的配置,即输出日志到名称为file,error的日志配置中
final Logger logger = Logger.getLogger(TestLog4j.class);
/*
#使某个功能的日志单独输出到指定的日志文件
log4j.logger.saveUserLog=INFO,saveUserLog
#该配置就是让job的日志只输出到自己指定的日志文件中,表示Logger不会在父Logger的appender里输出,默认为true。
log4j.additivity.saveUserLog=false
log4j.appender.saveUserLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.saveUserLog.File=d:\\test\\testlog4j\\saveUserLog.log
log4j.appender.saveUserLog.DatePattern=yyyy-MM-dd
log4j.appender.saveUserLog.Append=true
log4j.appender.saveUserLog.layout=org.apache.log4j.PatternLayout
log4j.appender.saveUserLog.layout.ConversionPattern=%m%n
*/
// 日志名称saveUserLog进行了单独的配置,因此不会使用log4j.rootLogger=info,file,error的配置
final Logger saveUserLog = Logger.getLogger("saveUserLog");
if (logger.isDebugEnabled()) {
logger.debug("debug");
}
logger.info("info");
logger.error("error");
saveUserLog.info("张三,男,26岁,北京大学,2018-05-19,学霸");
}
}
我们运行,输出如下:
注意提示log4j:WARN No appenders could be found for logger (dongshi.daddy.TestLog4j).
,对应的代码是final Logger logger = Logger.getLogger(TestLog4j.class)
,但是代码final Logger saveUserLog = Logger.getLogger("saveUserLog")
我们是进行了配置的,因此会成功生成日志文件,如下:
要消除警告我们可以有如下的两种方式,第一种是定义一个名称为dongshi.daddy.TestLog4j
的appener,如下:
# 定义名字为dongshi.daddy.TestLog4j的logger
log4j.logger.dongshi.daddy.TestLog4j=INFO,dongshi.daddy.TestLog4j
#该配置就是让job的日志只输出到自己指定的日志文件中,表示Logger不会在父Logger的appender里输出,默认为true。
log4j.additivity.dongshi.daddy.TestLog4j=false
log4j.appender.dongshi.daddy.TestLog4j=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dongshi.daddy.TestLog4j.File=d:\\test\\testlog4j\\dongshi.daddy.TestLog4j.log
log4j.appender.dongshi.daddy.TestLog4j.DatePattern=yyyy-MM-dd
log4j.appender.dongshi.daddy.TestLog4j.Append=true
log4j.appender.dongshi.daddy.TestLog4j.layout=org.apache.log4j.PatternLayout
log4j.appender.dongshi.daddy.TestLog4j.layout.ConversionPattern=%m%n
在运行查看:
此时警告就消失了,文件生成如下:
但是呢,这种配置方式有个问题就是,项目中logger的名称有很多很多,几乎一个类就有一个,如果每个都这样配置,那就太麻烦了,因此,可以采用第二种方式,即配置rootLogger
,这是一种统配appener
的配置方式,首先定义默认的日志级别,logger的名称,然后配置每个logger名称的详细配置,首先配置如下:
log4j.rootLogger=info,myfile,myerror
代表,默认的日志级别是info
,默认的日志名字是myfile,myerror
,然后分别配置日志的文件位置,输出格式等信息:
#配置error日志信息输出目的地Appender
#定义名为error的输出端是每天产生一个日志文件
log4j.appender.myfile=org.apache.log4j.DailyRollingFileAppender
#指定日志信息的最低输出级别位ERROR,默认为DEBUG。
log4j.appender.myfile.Threshold=ERROR
#myfile/log4j/error.log文件中
log4j.appender.myfile.File=d:\\test\\testlog4j\\myfile.log
#指定按月来滚动日志文件
log4j.appender.myfile.DatePattern=yyyy-MM
#配置日志信息的格式(布局)Layout是可以灵活地指定布局模式
log4j.appender.myfile.layout=org.apache.log4j.PatternLayout
#格式化日志,Log4j采用类似C语言中的printf函数的打印格式格式化日志信息
log4j.appender.myfile.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][jpm-%c{1}-%M(%L)]-%m%n
#指定输出信息的编码
log4j.appender.myfile.encoding=UTF-8
#配置error日志信息输出目的地Appender
#定义名为error的输出端是每天产生一个日志文件
log4j.appender.myerror=org.apache.log4j.DailyRollingFileAppender
#指定日志信息的最低输出级别位ERROR,默认为DEBUG。
log4j.appender.myerror.Threshold=ERROR
#myfile/log4j/error.log文件中
log4j.appender.myerror.File=d:\\test\\testlog4j\\myerror.log
#指定按月来滚动日志文件
log4j.appender.myerror.DatePattern=yyyy-MM
#配置日志信息的格式(布局)Layout是可以灵活地指定布局模式
log4j.appender.myerror.layout=org.apache.log4j.PatternLayout
#格式化日志,Log4j采用类似C语言中的printf函数的打印格式格式化日志信息
log4j.appender.myerror.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][jpm-%c{1}-%M(%L)]-%m%n
#指定输出信息的编码
log4j.appender.myerror.encoding=UTF-8
然后运行:
各种警告也都消失了,生成日志文件如下:
截止到这里我们其实并没有引入日志门面,但是在项目中一般都是面向日志门面接口来编写日志的,这里我们引入日志门面slf4j,修改如下:
<dependencies>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
dependencies>
org.slf4j.Logger saveUserLog = org.slf4j.LoggerFactory.getLogger("saveUserLog");
saveUserLog.info("slf4j info ...");
saveUserLog.error("slf4j error ...");
注意使用了slf4j的接口API,内部会动态的查找实现类,这里最终查找到的就是log4j,运行:
本例直接结合slf4j日志门面接口一起使用,logback作为slf4j的亲儿子,使用起来更加无缝衔接。
<dependencies>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-accessartifactId>
<version>1.2.3version>
dependency>
dependencies>
<configuration status="WARN" monitorInterval="30">
<appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %npattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="STDOUT1"/>
root>
configuration>
public class TestLogback {
public static void main(String[] args) {
final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(TestLogback.class);
LOGGER.debug("print debug log.");
LOGGER.info("print info log.");
LOGGER.error("print error log.");
}
}
运行:
157 [main] DEBUG dongshi.daddy.TestLogback - print debug log.
160 [main] INFO dongshi.daddy.TestLogback - print info log.
160 [main] ERROR dongshi.daddy.TestLogback - print error log.
Process finished with exit code 0
此时只配置了输出到控制台,接下来增加输出到文件中。
红框中的为增加内容,这里再贴下,方便看到的朋友测试:
<appender name="FILE1" class="ch.qos.logback.core.FileAppender">
<file>D:\\test\\testslf4jlogbck\\testlogback.logfile>
<append>trueappend>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%npattern>
encoder>
appender>
<appender-ref ref="FILE1"/>
log4j2是log4j的升级版本,同时支持日志门面JCL(Java commons logging),slf4j(simple logging facade for Java),下面看下使用。
一直以为log4j2是有一个专门的xxx.xxx.log4j2的pom,但其实log4j2就是log4j的2.x版本,汗!!!
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
log4j2.xml
<configuration status="WARN" monitorInterval="30">
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %logger{36} - %msg%n" />
console>
<File name="log" fileName="D:\\test\\testlog4j2\\log.log" append="true">
<PatternLayout
pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %logger{36} - %msg%n" />
File>
appenders>
<loggers>
<logger name="org.springframework" level="INFO">logger>
<logger name="org.mybatis" level="INFO">logger>
<root level="INFO">
<appender-ref ref="Console" />
<appender-ref ref="log" />
root>
loggers>
configuration>
public class TestLog4j2 {
public static void main(String[] args) {
final Logger LOGGER = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
LOGGER.debug("TestLog4j2 debug log.");
LOGGER.info("TestLog4j2 info log.");
LOGGER.error("TestLog4j2 error log.");
}
}
本部分使用JCLjava common logging
作为日志门面,使用log4j作为日志实现,具体如下。
<dependencies>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
dependencies>
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
log4j.rootLogger=debug,myfile,myerror,myconsole
log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
#指定日志信息的最低输出级别位ERROR,默认为DEBUG。
log4j.appender.myconsole.Threshold=DEBUG
#配置日志信息的格式(布局)Layout是可以灵活地指定布局模式
log4j.appender.myconsole.layout=org.apache.log4j.PatternLayout
#格式化日志,Log4j采用类似C语言中的printf函数的打印格式格式化日志信息
log4j.appender.myconsole.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][jpm-%c{1}-%M(%L)]-%m%n
#指定输出信息的编码
log4j.appender.myconsole.encoding=UTF-8
#配置error日志信息输出目的地Appender
#定义名为error的输出端是每天产生一个日志文件
log4j.appender.myfile=org.apache.log4j.DailyRollingFileAppender
#指定日志信息的最低输出级别位ERROR,默认为DEBUG。
log4j.appender.myfile.Threshold=INFO
#myfile/log4j/error.log文件中
log4j.appender.myfile.File=d:\\test\\TestJclAndLog4j\\myfile.log
#指定按月来滚动日志文件
log4j.appender.myfile.DatePattern=yyyy-MM
#配置日志信息的格式(布局)Layout是可以灵活地指定布局模式
log4j.appender.myfile.layout=org.apache.log4j.PatternLayout
#格式化日志,Log4j采用类似C语言中的printf函数的打印格式格式化日志信息
log4j.appender.myfile.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][jpm-%c{1}-%M(%L)]-%m%n
#指定输出信息的编码
log4j.appender.myfile.encoding=UTF-8
#配置error日志信息输出目的地Appender
#定义名为error的输出端是每天产生一个日志文件
log4j.appender.myerror=org.apache.log4j.DailyRollingFileAppender
#指定日志信息的最低输出级别位ERROR,默认为DEBUG。
log4j.appender.myerror.Threshold=ERROR
#myfile/log4j/error.log文件中
log4j.appender.myerror.File=d:\\test\\TestJclAndLog4j\\myerror.log
#指定按月来滚动日志文件
log4j.appender.myerror.DatePattern=yyyy-MM
#配置日志信息的格式(布局)Layout是可以灵活地指定布局模式
log4j.appender.myerror.layout=org.apache.log4j.PatternLayout
#格式化日志,Log4j采用类似C语言中的printf函数的打印格式格式化日志信息
log4j.appender.myerror.layout.ConversionPattern=[%d{yyyy-MM-ddHH:mm:ss}][%-5p][jpm-%c{1}-%M(%L)]-%m%n
#指定输出信息的编码
log4j.appender.myerror.encoding=UTF-8
public class TestJclAndLog4j {
public static void main(String[] args) {
final org.apache.commons.logging.Log LOGGER = org.apache.commons.logging.LogFactory.getLog(TestJclAndLog4j.class);
LOGGER.debug("TestJclAndLog4j debug log.");
LOGGER.info("TestJclAndLog4j info log.");
LOGGER.error("TestJclAndLog4j error log.");
}
}
参考文章列表:
https://zhuanlan.zhihu.com/p/64353891
https://www.cnblogs.com/warking/p/5710303.html