并不存在一些行为和习惯会比其他的行为和习惯更有意义,很多观点是大部分人一致认为那是有意义的。人要活出自己,对未来充满希望,积极面对人生。不要嫌弃与我行为,认知,和感受不同的人,我会保持自己的生活方式,即使自己不能接受其他人相反的方式,但并不妨碍我去理解并尊重与我不同的人,而且真心为他们的快乐而感到开心和祝福
目的
搞懂下面这两行代码到底是怎么打印出日志的
private static final Logger logger=Logger.getLogger(Log4jTest.class);
logger.debug(“log4j debug message”);
完整代码如下
package com.fjp.log.logClass;
import org.apache.log4j.Logger;
public class Log4jTest {
private static final Logger logger=Logger.getLogger(Log4jTest.class);
public static void main(String[] args){
if(logger.isDebugEnabled()){
logger.debug("log4j debug message");
}
if(logger.isInfoEnabled()){
logger.debug("log4j info message");
}
/*输出:
* 2021-07-08 18:57:04 log4j debug message
2021-07-08 18:57:04 log4j info message
* */
}
}
依赖如下
<!--log4j 依赖 start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--log4j 依赖 end -->
配置文件
### 设置###
### 配置根 Logger,语法如下所示
### log4j.rootLogger = [ level ] , appenderName, appenderName, … level 控制打印级别
log4j.rootLogger = TRACE,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 级别以上的日志到=debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = debug.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 级别以上的日志到=error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =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
文件位置
源码分析
- 分析Logger.getLogger(Log4jTest.class) 内部在干嘛
private static final Logger logger=Logger.getLogger(Log4jTest.class);
Logger.getLogger(Class clazz) 方法分析
LogManager.getLogger(clazz.getName());此行分两步看:
1 [先LogManager的static 块 ]
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h); // 赋值好repositorySelector
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);//关键步骤 加载的路径是log4j.properites
//关键步骤 不同类型配置对应的解析器 如果是xml 用org.apache.log4j.xml.DOMConfigurator 而properties 用org.apache.log4j.PropertyConfigurator
OptionConverter.selectAndConfigure(url, configuratorClassName,LogManager.getLoggerRepository());
configurator = new PropertyConfigurator(); // properties 文件解析器
configurator.doConfigure(url, hierarchy);
doConfigure(props, hierarchy); // 详细解析不关心
2 [getLogger]
getLoggerRepository().getLogger(name);
Hierarchy类:
getLogger(name, defaultFactory);
getLogger(name, defaultFactory);
CategoryKey key = new CategoryKey(name); //key
logger = factory.makeNewLoggerInstance(name);//关键步骤 工厂创建一个logger
ht.put(key, logger); //关键步骤 把logger 放进一个hashtable里,
总结流程:
- 第一步: 引发LogManager的类初始化
- 第二步:
初始化一个logger仓库Hierarchy
LoggerFactory defaultFactory: 就是创建Logger的工厂
Hashtable ht:用来存放上述工厂创建的Logger
Logger root:作为根Logger - 第三步:在LogManager的类初始化的过程中默认寻找类路径下的配置文件
- 第四步:解析上述配置文件
- 第五步:当一切都准备妥当后,就该获取Logger了
- 分析 logger.debug(“log4j debug message”);
logger.debug("log4j debug message");
类Category
forcedLog(FQCN, Level.DEBUG, message, null);
// 调用appenders 输出
callAppenders(new LoggingEvent(fqcn, this, level, message, t)); //LoggingEvent 封装了打印的信息
writes += c.aai.appendLoopOnAppenders(event);
类:AppenderAttachableImpl
appender.doAppend(event);
类:AppenderSkeleton
doAppend(LoggingEvent event)
Filter f = this.headFilter; // 过滤
this.append(event);
类:WriterAppender
subAppend(event);
this.qw.write(this.layout.format(event)); //格式化内容
this.qw.flush(); //刷出日志到 控制台
总结步骤:
- 第一步 封装打印信息 LoggingEvent
- 第二步 调用每个appender
- 第三步 调用fileter
- 第四步 layout格式化输出内容
- 第五步 刷出日志到 控制台