log4j 性能

2022-09-03 13:16:19

我正在开发一个Web应用程序,我想记录一些信息来帮助我改进和观察该应用程序(我正在使用Tomcat6)

首先,我想我会使用StringBuilders,将日志附加到它们,然后任务将它们持久保存到数据库中,就像每2分钟一次一样。因为我担心开箱即用的日志记录系统的性能。然后我做了一些测试。特别是使用log4j。

这是我的代码:

主要.java

public static void main(String[] args) {
  Thread[] threads = new Thread[LoggerThread.threadsNumber];

  for(int i = 0; i < LoggerThread.threadsNumber; ++i){
   threads[i] = new Thread(new LoggerThread("name - " + i));
  }
  LoggerThread.startTimestamp = System.currentTimeMillis();

  for(int i = 0; i < LoggerThread.threadsNumber; ++i){
   threads[i].start();
  }

记录器线程.java

public class LoggerThread implements Runnable{
 public static int threadsNumber = 10;
 public static long startTimestamp;
 private static int counter = 0;
 private String name;

 public LoggerThread(String name) {
  this.name = name;
 }
 private Logger log = Logger.getLogger(this.getClass());

 @Override
 public void run() {
  for(int i=0; i<10000; ++i){
   log.info(name + ": " + i);

   if(i == 9999){
    int c = increaseCounter();

    if(c == threadsNumber){
     System.out.println("Elapsed time: " + 
       (System.currentTimeMillis() - startTimestamp));
    }
   }

  }
 }

 private synchronized int increaseCounter(){
  return ++counter;
 }

}
     }

log4j.properties

log4j.logger.main.LoggerThread=debug, f
log4j.appender.f=org.apache.log4j.RollingFileAppender
log4j.appender.f.layout=org.apache.log4j.PatternLayout
log4j.appender.f.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.f.File=c:/logs/logging.log
log4j.appender.f.MaxFileSize=15000KB
log4j.appender.f.MaxBackupIndex=50

我认为这是log4j的一个非常常见的配置。首先我使用log4j 1.2.14,然后我意识到有一个更新的版本,所以我切换到1.2.16

以下是数字(全部以毫秒为单位)

LoggerThread.threadsNumber = 10

1.2.14: 4235, 4267, 4328, 4282
1.2.16: 2780, 2781, 2797, 2781

LoggerThread.threadsNumber = 100

1.2.14: 41312, 41014, 42251
1.2.16: 25606, 25729, 25922

我认为这非常快。不要忘记:在每个循环中,run方法不仅登录到文件,还必须连接字符串,并检查if测试。(name + ": " + i)(i == 9999)

当 threadsNumber 为 10 时,有 100.000 个日志记录以及 if 测试和串联。当它是 100 时,有 1.000.000 个日志记录以及 if 测试和串联。(我在某个地方读到JVM使用StringBuilder的附加进行串联,而不是简单的串联)。

我错过了什么吗?我做错了什么吗?我是否忘记了任何可能降低性能的因素?如果这些数字是正确的,我想我不必担心log4j的性能,即使我大量记录,我呢?

我读过:“实际记录的典型成本约为100到300微秒。这是正确的吗?(log4J 手册)


答案 1

如果性能是一个问题,请务必特别注意模式布局文档,并避免昂贵的转换字符,如 C、F、L 和 M。这些需要恶作剧来检索此信息。

在 C 中,使用 c 并在创建 Logger 对象时适当地命名它们。这意味着您不能从父类继承记录器,但重新定义记录器的不便值得提高性能。F、L 和 M 的功能没有简单的替代品,但措辞良好的日志消息应该很容易在源代码中找到,因此减少了指定确切方法、文件和行的需求。

最后,避免在日志消息中使用动态字符串串联。当需要使用串联时,请确保将该日志记录字符串的创建包装在相应的检查器方法中。

private final static Logger LOG = Logger.get(MyClass.class);
...
void someMethod() {
    if (LOG.isDebugEnabled()) {
        LOG.debug("some really expensive string concatenation: " + someInstanceVariable + " a bunch of other text!");
    }
}

isDebugEnabled() 始终以恒定时间运行。LOG.debug() 本身实质上在开始时执行 isDebugEnabled() 检查,但作为参数传递的字符串必须完全构建,然后才能进行该检查,从而在关闭调试级别时导致不必要的延迟。


答案 2

我不必担心log4j的性能,即使我大量记录

完全。在性能分析结果告诉您之前,不要进行优化。在某些情况下,日志记录性能是一个瓶颈,但您需要首先遇到这种情况,然后针对它进行优化。


推荐