一、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. eclipse中访问不了tomcat首页server Locations变灰无法编辑

    eclipse中访问不了tomcat首页server Locations变灰无法编辑 2014年07月25日 14:37:21 wuha0 阅读数:19139更多 个人分类: servlet   解决 ...

  2. jquery slideDown 控制div出现的方向

    .custom-popup { position: absolute; /*top: 0;*/ 上向下 ; 下向上 ; ; display: none; width: 100%; height: 10 ...

  3. 利用Excel-Vba进行多表汇总和数据透视表

    汇总表格式 详情表格式 要求根据汇总表中的信息,到详情表中查找详细物料的具体个数 最终,对物料的个数进行汇总,结果如下图: ExcelVba代码如下(有一些注释代码供参考) Sub Start() S ...

  4. html+css+javascript之间的关系与作用

    三者间的关系 一个基本的网站包含很多个网页,一个网页由html, css和javascript组成. html是主体,装载各种dom元素:css用来装饰dom元素:javascript控制dom元素. ...

  5. Firefox下载附件乱码的解决办法

    通过在http的header里设置fileName下载附件时,中文文件名通过chrome浏览器下载时正常,通过firefox下载时为乱码: 原来的Java代码: response.addHeader( ...

  6. Java的类型强制转换

    不说基本类型,没什么意思. 小括号的类型转换,在引用上,表示我坚定的确信,该未知类型一定是我转的类型,或者是我转的类型的子类. 这个转换逻辑和基本类型是不一致的.它不会进行任何具体的操作,只是一种标识 ...

  7. L2-007 家庭房产 (25 分)

    L2-007 家庭房产 (25 分)   给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数.人均房产面积及房产套数. 输入格式: 输入第一行给出一个正整数N(≤),随后N行,每行按下 ...

  8. JAVA对mongodb的基本操作

    public class test3 { //连接数据库(不需要验证,用于测试连接本地的mongodb) public static MongoDatabase getDatabase(String ...

  9. oracle mysql 比较

    转载:https://www.cnblogs.com/qq765065332/p/9293029.html 一.数据的存储结构 mysql: 1.对数据的管理可以有很多个用户,登录用户后可以看到该用户 ...

  10. eclipse使用技巧心得分享

    eclipse使用技巧心得分享   习惯了eclipse开发java程序,公司最近的项目都是idea开发的,同时android studio也是idea原型开发的,在学android开发,所以脱离ec ...