log4j性能

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

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

这是我的代码:

Main.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(); } 

LoggerThread.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方法不仅仅是登录文件,还必须连接字符串(name + ": " + i) ,并检查if test (i == 9999)

当threadsNumber为10时,有100,000个记录,如果是测试和连接。 当它为100时,有1.000.000个记录,如果测试和连接。 (我在某处读过JVM使用StringBuilder附加的连接,而不是简单的连接)。

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

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

是的,由于其实现者的有意识的努力,Log4J被认为是快速的。 另请参阅Log4J简介末尾的“性能”部分。

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

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

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

 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()检查,但是在该检查发生之前必须完全构建作为参数传递的字符串,从而在关闭调试级别时导致不必要的延迟。

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

究竟。 在分析结果告诉您之前不要进行优化。 有些情况下,当日志记录性能成为瓶颈时,您首先需要遇到这种情况,然后针对它进行优化。

瓶颈应该是硬盘。 你的测试显示大约1MB / s的磁盘写入速度,实际上相当差。

确保您有适当的日志记录策略。 这意味着确保定义要记录的内容,并将其分为调试,跟踪,信息,警告和错误以及其他一些(如果需要)。 还要确保您能够根据需要打开和关闭它以执行性能/调试。

日志记录会对使用频繁的站点/应用程序产生重大影响。记录太多会为您提供比您可以排序的更多信息。 记录有时是您唯一的事件后调试工具,因此请确保您的计数。

如果性能真的是一个问题,请查看slf4j: http ://www.slf4j.org/manual.html

使用占位符方法时,当您禁用日志记录时,它们比log4j更快,因为在log4j中,字符串连接独立地发生,实际上需要消息。 如果真正记录此消息,Slf4j仅替换占位符。

但你可以在log4j中做这样的事情:

 if(l.isDebugEnabled()) l.debug("log entry: " + 7); 

但我认为这是很多样板代码所以我使用的是slf4j

必须注意的是,log4j在大量并发使用时会遭受许多锁定疼痛。

我的另一个答案的更多细节和一些解决方法: log4j的生产设置文件?