一、slf4jlog4j的关系:

也就是说slf4j仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已。必须搭配具体的log实现方案比如说log4j jdklogging等等,中间需要适配层做桥接,例如slf4j与log4j的桥接包:slf4j-log4j12-1.6.1.jar。

二、log4j加载过程:

代码中的用法一般如下:

Logger myLog = LoggerFactory.getLogger(XXXX.class);\

myLog.info(“this is info log text”);

myLog.error(“this is error log text”);

1、获取Logger对象步骤:

(1) 获取StaticLoggerBinder的单例对象;

(2) StaticLoggerBinder对象里有一个Log4jLoggerFactory对象,Log4jLoggerFactory对象里面有一个存储了Logger对象的hash表:

loggerMap = new ConcurrentHashMap<String, Logger>();

(3) getLogger(XXXX.class)时首先查这个hash表,如果查询到则直接返回,否则创建Log4jLoggerAdapter对象并添加到这个hash表中;

2、日志记录:

(1) Log4jLoggerAdapter对象作为Logger对象的代理对象,所有记录日志的info, error等方法都是传递到Logger对象去执行处理的;

三、Log4j配置文件解析过程:

Log4jLoggerFactory在构造函数中会调用LogManager的getRootLogger方法,LogManager的静态初始方法块中会检查配置文件并加载,可以是指定的Class类,也可以是xml格式配置文件,也可以是properties格式的配置文件;对于properties格式的配置文件,使用PropertyConfigurator类来读取和解析配置信息;

Properties格式的log4j的配置文件说明:

#Log4J配置文件实现了输出到控制台、文件、回滚文件、自定义标签,数据库等功能。仅供参考。

log4j.rootLogger=DEBUG,CONSOLE,FILE,DLOGFILE,ROLLING_FILE,MYSQL_LOG

log4j.addivity.org.apache=true

#应用于控制台

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender

log4j.appender.CONSOLE.Threshold=DEBUG

log4j.appender.CONSOLE.Target=System.out

log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout

log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n

#应用于文件

log4j.appender.FILE=org.apache.log4j.FileAppender

log4j.appender.FILE.File=d:\\file.log

log4j.appender.FILE.Append=false

log4j.appender.FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.FILE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n

#应用于按日期生成文件

log4j.appender.DLOGFILE=org.apache.log4j.DailyRollingFileAppender

log4j.appender.DLOGFILE.File=d:\\test.log

log4j.appender.DLOGFILE.Threshold=INFO

log4j.appender.DLOGFILE.DatePattern='.'yyyy-MM-dd

log4j.appender.DLOGFILE.layout=org.apache.log4j.PatternLayout

log4j.appender.DLOGFILE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n

#应用于文件回滚

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender

log4j.appender.ROLLING_FILE.Threshold=INFO

log4j.appender.ROLLING_FILE.File=d:\\rolling.log

log4j.appender.ROLLING_FILE.Append=true

log4j.appender.ROLLING_FILE.MaxFileSize=1KB

log4j.appender.ROLLING_FILE.MaxBackupIndex=1

log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.ROLLING_FILE.layout.ConversionPattern=%d{yyyyMMdd-HH:mm:ss} %t %c %m%n

# 数据库输出

log4j.appender.MYSQL_LOG=org.apache.log4j.jdbc.JDBCAppender

log4j.appender.MYSQL_LOG.driver=com.mysql.jdbc.Driver

log4j.appender.MYSQL_LOG.URL=jdbc:mysql://127.0.0.1:3306/txl

log4j.appender.MYSQL_LOG.Threshold=ERROR

log4j.appender.MYSQL_LOG.user=root

log4j.appender.MYSQL_LOG.password=

log4j.appender.MYSQL_LOG.sql=insert into log_monitor(level,category,thread,time,location,note) values('%p','%c','%t','%d{yyyy-MM-dd HH:mm:ss:SSS}','%l','%m')

log4j.appender.MYSQL_LOG.layout=org.apache.log4j.PatternLayout

#虽然以上布局 没啥效果,但是可以减少告警提示

#自定义Appender ,输出到任意地方

四、Log4j组件:

1.Logger:

继承Category(一种日志类),提供不同级别的日志接口(例:logger.info,logger.error等);当调用方调用了info, error等方法记录日志时,调用的是Log4jLoggerAdapter的方法,然后Log4jLoggerAdapter又将调用转给Logger对象去执行;

2.Appender:

appender就是日志输出地;日志的记录输出抽象,大致有控制台输出,文件输出等;

Logger对象在记录日志时,会遍历Logger对象上注册的所有Appender以及父类上注册的Appender,然后依次调用所有Appender的appendLoopOnAppenders方法记录日志;

主要实现类有WriteAppender,ConsoleAppender,FileAppender;WriterAppender将日志写入Java IO中,它继承自SkeletonAppender类。它引入了三个字段:immediateFlush,指定每写完一条日志后,即将日志内容刷新到设备中,因而一般推荐将该值设置为true,即默认值;econding用于定义日志文本的编码方式;qw定义写日志的writer,它可以是文件或是控制台等Java IO支持的流;

FileAppender的子类主要有DailyRollingFileAppender和RollingFileAppender:DailyRollingFileAppender会在每隔一段时间可以生成一个新的日志文件,不过这个时间间隔是可以设置的,不仅仅只是每隔一天。时间间隔通过setDatePattern()方法设置,datePattern必须遵循SimpleDateFormat中的格式;RollingFileAppender则是基于文件大小作为阀值。当日志文件超过指定大小,日志文件会被重命名成”日志文件名.1”,若此文件已经存在,则将此文件重命名成”日志文件名.2”,一次类推。若文件数已经超过设置的可备份日志文件最大个数,则将最旧的日志文件删除。如果要设置不删除任何日志文件,可以将maxBackupIndex设置成Integer最大值。

3.Layout:

实现了OptionHandler的抽象类;主要是对日志行的格式进行限定,常用有PatternLayout和HTMLLayout;

4.LoggerRepository:

常见的Hirearchy为其实现类,封装了框架的默认配置,还有Logger工厂,事件源,封装了一些列事件。

5.LoggingEvent:

封装了消息内容、级别、记录器类名的全名称等信息;当记录日志时,会将日志内容封装成LoggingEvent对象并调用Logger对象进行记录;

五、流程图:

1、调用方调用LoggerFactory.getLogger(XXXX.class)时,首先获取具体日志实现框架的LoggerFactory类Log4jLoggerFactory,在Log4jLoggerFactory.getLogger(XXXX.class)时,首先从hashMap里面去获取,如果获取不到则创建,创建时首先获取getLoggerRepository(也就是Hierarchy),然后在Hierarchy的hashMap里面去获取,如果找到则直接返回,否则创建新的Logger对象并添加到hashMap里面后返回;

2、记录日志时调用的info, debug, error等方法都是调用的适配器对象Log4jLoggerAdapter里面的方法,Log4jLoggerAdapter会将调用转到Logger对象上;接着判断Logger实例对应的日志记录级别(每个Logger实例都有自己的Level)是否要比请求的级别低→若是则调用forcedLog记录日志;

3、接着创建LoggingEvent实例→将LoggingEvent实例传递给appender,Appender调用Layout实例格式化日志消息;最后Appender将格式化后的日志信息写入改Appender对应的日志输出中。

六、相关问题:

1.如何实现log4j和slf4j的解耦:也即如何实现将log4j的实现绑定到slf4j的接口定义上?

LoggerFactory的绑定:

LoggerFactory是一个定义在slf4j-api中的类,其getLogger通过StaticLoggerBinder的单实例对象获取到ILoggerFactory对象,StaticLoggerBinder是在slf4j-log4j插件里面定义的;最后获取Logger对象是在LogManager中创建Logger对象并返回的,LogManager和Logger对象都是在实现jar包log4j里面实现的;

2.Appender是如何注册到Logger上的?

PropertyConfigurator类的parseCategory方法解析配置文件log4j.properties的代码:

void parseCategory(Properties props, Logger logger, String optionKey,

String loggerName, String value) {

...................

// Begin by removing all existing appenders.

logger.removeAllAppenders();

Appender appender;

String appenderName;

while(st.hasMoreTokens()) {

appenderName = st.nextToken().trim();

if(appenderName == null || appenderName.equals(","))

continue;

LogLog.debug("Parsing appender named \"" + appenderName +"\".");

appender = parseAppender(props, appenderName);

      if(appender != null) {

logger.addAppender(appender);

      }

}

}

LogManager的静态代码中检测到配置文件log4j.properties的路径并加载这个配置文件,然后执行parseCategory方法解析配置文件;上面加粗部分,parseAppender会根据log4j.properties配置文件生成appender对象,然后将其添加到logger对象上;

七、参考资料:

https://my.oschina.net/xianggao/blog/518059

https://www.cnblogs.com/zeng-wei/archive/2012/08/28/2660363.html

https://blog.csdn.net/m0_37652164/article/details/80487522

https://blog.csdn.net/u011794238/article/details/50736331/

http://wiki.10101111.com/pages/viewpage.action?pageId=190240215

http://www.cnblogs.com/question-sky/p/7425069.html

http://www.cnblogs.com/question-sky/p/7429548.html

http://www.cnblogs.com/question-sky/p/7469596.html

https://www.cnblogs.com/question-sky/p/8436366.html

http://www.blogjava.net/DLevin/archive/2012/06/28/381667.html

http://www.blogjava.net/DLevin/archive/2012/11/04/390755.html

Log4j源码分析的更多相关文章

  1. java 日志体系(四)log4j 源码分析

    java 日志体系(四)log4j 源码分析 logback.log4j2.jul 都是在 log4j 的基础上扩展的,其实现的逻辑都差不多,下面以 log4j 为例剖析一下日志框架的基本组件. 一. ...

  2. commons-logging + log4j源码分析

    分析之前先理清楚几个概念 Log4J = Log For Java SLF4J = Simple Logging Facade for Java 看到Facade首先想到的就是设计模式中的门面(Fac ...

  3. Log4j漏洞源码分析

    Log4j漏洞源码分析 这几天Log4j的问题消息满天飞,今天我们就一起来看看从源码角度看看这个漏洞是如何产生的. 大家都知道这次问题主要是由于Log4j中提供的jndi的功能. 具体涉及到的入口类是 ...

  4. YARN DistributedShell源码分析与修改

    YARN DistributedShell源码分析与修改 YARN版本:2.6.0 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 概述 2 YARN Distrib ...

  5. springmvc源码分析

    Spring MVC源码分析--初始化过程 标签: springmvcconstructioniocclass 2012-09-09 21:32 26578人阅读 评论(3) 收藏 举报 版权声明:本 ...

  6. Solr4.8.0源码分析(15) 之 SolrCloud索引深入(2)

    Solr4.8.0源码分析(15) 之 SolrCloud索引深入(2) 上一节主要介绍了SolrCloud分布式索引的整体流程图以及索引链的实现,那么本节开始将分别介绍三个索引过程即LogUpdat ...

  7. Solr4.8.0源码分析(4)之Eclipse Solr调试环境搭建

    Solr4.8.0源码分析(4)之Eclipse Solr调试环境搭建 由于公司里的Solr调试都是用远程jpda进行的,但是家里只有一台电脑所以不能jpda进行调试,这是因为jpda的端口冲突.所以 ...

  8. Nimbus<二>storm启动nimbus源码分析-nimbus.clj

    nimbus是storm集群的"控制器",是storm集群的重要组成部分.我们可以通用执行bin/storm nimbus >/dev/null 2>&1 &a ...

  9. log4j源码解析-文件解析

    承接前文log4j源码解析,前文主要介绍了log4j的文件加载方式以及Logger对象创建.本文将在此基础上具体看下log4j是如何解析文件并输出我们所常见的日志格式 附例 文件的加载方式,我们就选举 ...

随机推荐

  1. ajax 提交form格式 和 json格式

    json 格式 内容在body中 ajax设置   Content-Type: application/json 浏览器查看为 Request Payload The Request Payload ...

  2. API响应

    保证API响应的正确性,就是你需要做的大部分工作.postman的response viewer部分会协助你完成该工作且使其变得简单. 一个API的响应包含body,headers,响应状态码.pos ...

  3. Spine用于Timeline(NullReferenceException: Object reference not set to an instance of an object pine.Unity.Editor.AnimationReferenceAssetEditor.OnInspectorGUI ())

    报错信息:Spine.Unity.Editor.AnimationReferenceAssetEditor.OnInspectorGUI () (at Assets/Extention/Spine/E ...

  4. 剑指offer第32题:把数组排成最小的数及关于list.sort()和sorted( Iterable object )函数的相关知识

     * 解题思路:  * 先将整型数组转换成字符数组,然后将String数组排序,最后将排好序的字符串数组拼接出来.关键就是制定比较规则.  * 排序规则如下:  * 若ab > ba 则 a & ...

  5. ubuntu16.04运行ros的时候编译工作空间catkin_make出现的一个问题Could not find a package configuration file provided by

    最近在进行ros里面的gazebo仿真之前需要对自己创建的工作空间进行编译,但是进行编译的时候输入catkin_make出现如下错误提示 查阅ROS问答社区之后发现两个比较有用的链接,如下 https ...

  6. find a lover

    #version_s#1.8#version_e# #update_s#https://files.cnblogs.com/files/dyh221/update_1.zip#update_e#

  7. 使用lua实现99乘法口诀表,就这么简洁

    for i=1,9 do for j=1,i do io.write(j,"*",i,"=",i*j," ") end print() en ...

  8. python—文件创建

    # 1.文件操作# day1.txt# 1.文件路径:E:\day1.txt# 2.编码方式:utf-8.gbk# 3.操作方式:只读,只写,追加,读写,写读# 以什么编码方式储存的方式储存就以什么编 ...

  9. 匹配URL

    使用一个不错的正则表达式来配对一个正确的url. string reg = @"(?i)(http://|https://)?(\w+\.){1,3}(com(\.cn)?|cn|net|i ...

  10. 记一次Vue中v-model和v-bind区别

    由于v-model 只是语法糖, <input v-model="message"> 与下面的两行代码是一致的: <input v-bind:value=&quo ...