log4j的实现原理与思考

系列

log4j的介绍

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是 控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
  • 该篇内容涵盖了log4j日常的基本用法,深入分析了log4j的各功能组件、日志输出过程,以及提出了扩展性的一些思考。


log4j的基本用法

log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="https://jakarta.apache.org/log4j/" threshold="info" debug="false">

    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %c{1} - %m%n" />
        </layout>
        <filter class="org.apache.log4j.varia.LevelMatchFilter">
            <param name="LevelToMatch" value="INFO" />
            <param name="AcceptOnMatch" value="true" />
        </filter>
        <filter class="org.apache.log4j.varia.DenyAllFilter"/>
    </appender>

    <appender name="file" class="org.apache.log4j.RollingFileAppender">
        <param name="File" value="logs/main.log" />
        <param name="Append" value="true" />
        <param name="ImmediateFlush" value="true" />
        <param name="MaxFileSize" value="10MB" />
        <param name="MaxBackupIndex" value="5" />

        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %d{Z} [%t] %-5p (%F:%L) - %m%n" />
        </layout>
    </appender>

    <logger name="com.journaldev.log4j" additivity="true">
        <level value="DEBUG" />
        <appender-ref ref="jdbc" />
    </logger>

    <logger name="com.journaldev.log4j.model" additivity="true">
        <level value="DEBUG" />
        <appender-ref ref="file" />
    </logger>

    <root>
        <priority value="DEBUG" />
        <appender-ref ref="console" />
    </root>

</log4j:configuration>
  • log4j.xml的基础配置模板,配置包含appender、layout、filter、logger、root。
  • Appender是对记录日志形式的抽象,标示了日志打印的目的地。
  • Filter是对日志是否输出的过滤器,标识了日志是否能够打印。
  • Layout是对日志行格式的抽象。
  • 关键字threshold用来控制log4j整体的日志级别,低于该级别的日志不被输出。
  • 关键字debug用来日志log4j应用本身的启动日志。
  • 关键字additivity用来控制logger的继承属性。

log4j使用

public static void main(String[] args) {
  DOMConfigurator.configure("log4j.xml");
  Logger logger = Logger.getLogger("org.apache.log4j.xml");

  logger.info("++++++++++");
}
  • log4j的使用本质上是通过配置解析器解析指定的log4j.xml文件来生成Logger对象。
  • spring在使用log4j的过程中本质上也是加载了指定resources目录下的log4j.xml文件。


log4j的核心组件介绍

  • LoggingEvent是对一次日志记录过程中所需要的信息的抽象,可以理解成一个上下文。
  • Logger 用于对日志记录行为的抽象,提供记录不同级别日志的统一接口。
  • Appender是对记录日志形式的抽象,标示了日志打印的目的地。
  • Filter是对日志是否输出的过滤器,标识了日志是否能够打印。
  • Layout是对日志行格式的抽象。
  • Level对日志级别的抽象。

log4j组件关系

// LogManager包含Hierarchy对象
public class LogManager {
  static private RepositorySelector repositorySelector;
  static {
    Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));// Hierarchy保存Logger的所有信息
    repositorySelector = new DefaultRepositorySelector(h);
  }
}

// Hierarchy包含Logger对象
public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
  Hashtable ht;   // 保存应用当中所有的Logger对象
  Logger root;    // 保存应用中的Root的Logger对象
  Level threshold; // 全局的日志打印范围
}

// Logger包含Appender对象
public class Category implements AppenderAttachable {
  protected String   name; // Logger的名字
  volatile protected Level level; // Logger的日志级别
  volatile protected Category parent; // Logger继承的父类
  AppenderAttachableImpl aai; //Logger的绑定的appender
  protected boolean additive = true; // Logger的是否继承的标记
}

public class AppenderAttachableImpl implements AppenderAttachable {
  protected Vector  appenderList; // appender的列表
}

// Appender对象包含Layout对象和Filter对象。
public abstract class AppenderSkeleton implements Appender, OptionHandler {
  protected Layout layout; // appender绑定的layout对象
  protected String name; // append的名称
  protected Priority threshold;
  protected Filter headFilter; // append绑定的filter列表的头指针
  protected Filter tailFilter;// append绑定的filter列表的尾指针
}
  • LogManager包含Hierarchy对象。
  • Hierarchy包含多个Logger对象的Map。
  • Logger包含多个Appender对象列表。
  • Appender对象包含Layout对象。
  • Appender对象包含多个Filter对象的列表。

appender

org.apache.log4j.Appender(Appender的实现接口)

org.apache.log4j.net.SyslogAppender(打到远程日志服务器)
org.apache.log4j.jdbc.JDBCAppender(保存到数据库)
org.apache.log4j.RollingFileAppender(滚动文件,自动记录最新日志) 
org.apache.log4j.ConsoleAppender (控制台)  
org.apache.log4j.FileAppender (文件) 
org.apache.log4j.DailyRollingFileAppender (每天产生一个日志文件) 
org.apache.log4j.WriterAppender (将日志信息以流格式发送到任意指定的地方) 
  • log4j本身包含如SyslogAppender等日志输出类,也可以通过实现Appender接口定制满足特殊需求。

Layout

org.apache.log4j.Layout

org.apache.log4j.helpers.DateLayout
org.apache.log4j.PatternLayout
org.apache.log4j.SimpleLayout
  • log4j本身包含PatternLayout等日志输出类,也可以通过实现Layout接口定制满足特殊需求。

filter

org.apache.log4j.spi.Filter(Filter的实现接口)

org.apache.log4j.varia.LevelRangeFilter(日志等级范围过滤器)
org.apache.log4j.varia.StringMatchFilter(字符串匹配过滤器)
org.apache.log4j.varia.DenyAllFilter(拒绝所有日志的过滤器)
org.apache.log4j.varia.LevelMatchFilter(日志等级匹配过滤器)
  • log4j本身包含如LevelRangeFilter等过滤类,也可以通过实现Filter接口定制满足特殊需求。

log4j的日志输出过程

  • application通过LogManager的getLogger(name)来获取指定的Logger对象并调用info(msg)打印日志。
  • Logger.info()过程先判断满足全局的日志级别和Logger本身的日志级别,不满足直接返回。
  • Logger.info()在满足日志的级别的前提下构建日志对象LoggingEvent,并通过appender进行日志输出。
  • Logger.info()在会遍历Logger下appender对象列表,针对每个appender依次遍历Filter进行过滤。
  • Logger.info()在通过Layout对象格式化LoggingEvent日志对象并最终输出。
  • Logger对象若配置多个appender则同时输出多份日志,appender中多个Filter任意拒绝则拒绝输出日志。


log4j的配置解析过程

  • log4j通过DOMConfigurator解析log4j.xml文件,通过PropertyConfigurator解析log4j.property文件。
  • 通过Configurator的解析过程构建Logger、Appender、Layout、Filter的关系。


log4j的日常应用

  • 了解了log4j的整体日志输出框架,就可以掌握log4j本身支持的扩展点来实现一些特殊的需求,如拦截脱敏上报等功能。

appender日志级别输出定制

 想实现将系统所有的warn日志统一收集到common-warn.log中,将系统所有的error日志统一收集到common-error.log中,通过配置appender当中的LevelRangeFilter过滤器来实现定制不同日志级别的日志输出。

日志脱敏

 想实现对日志中敏感信息进行脱敏,log4j打印日志最终是通过Appender来输出通过Layout格式化的日志,可以在自定义Appender或者自定义Layout来实现脱敏功能,当然暂时不考虑性能问题,只考虑可行性。

日志上报打点

 想实现通过打印日志来实现异常次数采集监控,log4j打印日志最终是通过Appender来输出日志,可以通过自定义Appender来实现日志拦截上报打点,也可以自定义Filter过滤器在过滤器执行过程中实现日志拦截上报打点。
 笔者所在的公司就是通过工程启动的时候在指定的logger对象的appender当中添加自定义的Filter对象来实现日志的拦截上报功能。

日志级别修改

 动态修改日志级别,LogManager提供动态获取Logger对象的接口进而可以修改日志级别。
 动态修改日志的Appender对象,Logger对象提供addAppender/removeAppender的扩展接口。
 动态修改日志的Filter对象,Appender对象提供addFilter的扩展接口。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容