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