El Psy Congroo

Log4j笔记

Log4j 1.2

性能注意点

  • 使用Slf4j
  • 使用if (logger.isDebugEnabled()) { ... }封装String连接或其他高开销的操作
  • 避免多次打印Stack trace
  • 尽量避免使用类名%C, 文件名%F, 方法名%M, 行号%L,性能开销很大official warning
  • 通过缓存减少IO次数
    • immediateFlush
      • 是否每次log event都flush到磁盘,默认为true,设置为false能提高性能,但是在系统崩溃时可能会丢失日志
    • bufferedIO
      • 默认为false时使用java.io.Writer,设置为ture则改用BufferedWriterbufferSize默认8K,可调整
  • 使用AsyncAppender
    • 使用addAppender封装普通Appender为异步
    • 通过独立的AsyncAppender-Dispatcher线程调用Appender
    • 通过bufferSize设置缓存的event数量,到上限时根据blocking参数(默认为true)决定阻塞还是丢弃后续event

性能测试

  • 场景:单线程写入20,000条日志到文件

    flush on, buffer off
    656/602/522
    flush on, buffer off, async
    469/454/460

    flush off, buffer off
    149/154/153
    flush off, buffer off, async
    153/140/134

    flush off, buffer on
    104/104/100

其他

  • Mapped Diagnostic Context (MDC)
    • 记录特定信息,用于输出到日志(使用threadlocal存储),如用户等
1
2
3
4
5
6
//.java
MDC.put("user", session.getUser());
//log4j.xml
<param name="ConversionPattern" value="%X{user} %-5p - %m%n" />
//log
[user: admin] INFO .......
  • 控制日志只输出到一个Appender
    • additivity="false"

在程序中控制Appender

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Set Level
Logger logger = Logger.getLogger(loggerName);
logger.setLevel(Level.INFO);
// Get All Appenders
Enumeration<Appender> appenders = LogManager.getRootLogger().getAllAppenders();
// Get your Appender from Enumeration,
if (appender instanceof AsyncAppender) {
// Get all internal Appenders user by Asyn Appender
Enumeration<Appender> mainAppenders = asyncAppender.getAllAppenders();
// Get Main Appender, and do your operations
mainFileAppender.setImmediateFlush(false);
mainFileAppender.setBufferedIO(false);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static void init(boolean flush, boolean buffered, boolean async) {
FileAppender fileAppender = new FileAppender();
fileAppender.setName("FileLogger");
fileAppender.setFile("benchmark.log");
fileAppender.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
fileAppender.setThreshold(Level.INFO);
fileAppender.setAppend(false);
fileAppender.setImmediateFlush(flush);
fileAppender.setBufferedIO(buffered);
fileAppender.activateOptions();
LogManager.getRootLogger().removeAllAppenders();
if (async) {
AsyncAppender asyncAppender = new AsyncAppender();
asyncAppender.addAppender(fileAppender);
LogManager.getRootLogger().addAppender(asyncAppender);
}
else {
LogManager.getRootLogger().addAppender(fileAppender);
}
}

参考