Java的日志体系随着时间的飞逝,逐渐变得庞大,市面上流行着许多日志技术,例如:log4j,jcl,jul,slf4j… 市场上为什么会存在这么多的日志技术呢? 首先Java在开发的时候,自带了jul,但是jul没有配置文件,如果要修改日志记录的格式,那么就需要去改Java源代码。因为这个不便出现了带有配置文件修改格式的log4j。但是因为日志技术太多,项目存在日志不统一的情况,出现了jcl。后期发现jcl效率不高,紧接着出现了slf4j… 本篇博文详细介绍市面上日志的主流技术以及主流框架技术使用的日志体系。
Log4j是Apache的一个开源项目
(1)依赖Jar包
<dependency>
<!--<groupId>log4j</groupId>-->
<!--<artifactId>log4j</artifactId>-->
<!--<version>1.2.12</version>-->
</dependency>
(2)核心类Logger
package org.apache.log4j;
public class Logger {
// Creation & retrieval methods:
public static Logger getRootLogger();
public static Logger getLogger(String name);
// 输出方法:
public void trace(Object message);
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);
// 通用打印方法:
public void log(Level l, Object message);
}
(3)日志调用级别
/**
ERROR 为严重错误 主要是程序的错误
WARN 为一般警告,比如session丢失
INFO 为一般要显示的信息,比如登录登出
DEBUG 为程序的调试信息
***/
public class Test {
private static Logger logger = Logger.getLogger(Test.class);
/**
* @param args
*/
public static void main(String[] args) {
// System.out.println("This is println message.");
// 记录debug级别的信息
logger.debug("This is debug message.");
// 记录info级别的信息
logger.info("This is info message.");
// 记录error级别的信息
logger.error("This is error message.");
}
}
4.配置文件 log4j.properties
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{
yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{
yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{
yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{
yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{
yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{
yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
jcl=Jakarta commons-logging ,是apache公司开发的一个抽象日志通用框架,本身不实现日志记录,依赖于第三方日志技术,底层通过一个数组存放具体的日志框架的类名,然后循环数组依次去匹配这些类名是否在app中被依赖了,如果找到被依赖的则直接使用,所以他有先后顺序。
1.依赖Jar包
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
2.基础使用
public class Test {
private static Log log = LogFactory.getLog(Test.class);
public static void main(String[] args) {
if (log.isInfoEnabled()) {
log.info("this is a debug msg!");
}
}
}
3.核心类 LogFactoryImpl.class 源码解析
通过一个类名去load一个class,如果load成功则直接new出来并且返回使用。如果没有load到class这循环第二个,直到找到为止。
slf4j他也不记录日志,通过绑定器绑定一个具体的日志记录来完成日志记录
1.绑定器
通过绑定器,slf4j与其它日志技术更好的绑定。
2.桥接
通常,依赖的某些组件依赖于SLF4J以外的日志API。您可能还假设这些组件在不久的将来不会切换到SLF4J。为了应对这种情况,SLF4J附带了几个桥接模块,这些模块会将对log4j,JCL和java.util.logging API的调用重定向为仿佛对SLF4J API进行的行为
只要按照文档使用,slf4j与项目依赖的日志桥接jar包就可以。
spring5.x改变了spring4.x直接依赖于jcl,改成了自己改写的spring-jcl。
查看核心类LogFactory:
public abstract class LogFactory {
private static LogFactory.LogApi logApi; //默认的
public LogFactory() {
}
public static Log getLog(Class<?> clazz) {
return getLog(clazz.getName());
}
//根据logApi的值选择logger类型
public static Log getLog(String name) {
switch(logApi) {
case LOG4J:
return LogFactory.Log4jDelegate.createLog(name);
case SLF4J_LAL:
return LogFactory.Slf4jDelegate.createLocationAwareLog(name);
case SLF4J:
return LogFactory.Slf4jDelegate.createLog(name);
default:
return LogFactory.JavaUtilDelegate.createLog(name);
}
}
//部分不太重要的代码,此处忽略
static {
//logApi的默认值
logApi = LogFactory.LogApi.JUL;
ClassLoader cl = LogFactory.class.getClassLoader();
//根据load的情况,动态更改logApi的值
try {
cl.loadClass("org.apache.logging.log4j.spi.ExtendedLogger");
logApi = LogFactory.LogApi.LOG4J;
} catch (ClassNotFoundException var6) {
try {
cl.loadClass("org.slf4j.spi.LocationAwareLogger");
logApi = LogFactory.LogApi.SLF4J_LAL;
} catch (ClassNotFoundException var5) {
try {
cl.loadClass("org.slf4j.Logger");
logApi = LogFactory.LogApi.SLF4J;
} catch (ClassNotFoundException var4) {
;
}
}
}
}
和传统的jcl(common-logging.jar)的区别是,首先是尝试加log4j2里面的一个ExtendedLogger,然后尝试加载slf4j SPI,再次就是尝试slf4j API如果没有就加载jul。
MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。它会使用第一个查找得到的工具(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。
1.Mybtis配置日志
可以通过在 MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择日志工具
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
你也可以调用如下任一方法来使用日志工具:
org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
org.apache.ibatis.logging.LogFactory.useLog4JLogging();
org.apache.ibatis.logging.LogFactory.useJdkLogging();
org.apache.ibatis.logging.LogFactory.useCommonsLogging();
org.apache.ibatis.logging.LogFactory.useStdOutLogging();
2.LogFactory解析
查看Mybatis的org.apache.ibatis.logging.LogFactory源码,了解Mybatis日志选择机制。
Mybtis的设计同样采用在无设置的情况下按顺序进行查找项目中的依赖。