美文网首页log4j
log4j的实现原理与思考

log4j的实现原理与思考

作者: 晴天哥_王志 | 来源:发表于2021-02-09 15:31 被阅读0次

系列

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的扩展接口。

相关文章

网友评论

    本文标题:log4j的实现原理与思考

    本文链接:https://www.haomeiwen.com/subject/tlqitltx.html