Java log4j 性能
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3053134/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
log4j performance
提问by Bob
I'm developing a web app, and I'd like to log some information to help me improve and observe the app. (I'm using Tomcat6)
我正在开发一个网络应用程序,我想记录一些信息以帮助我改进和观察应用程序。(我使用的是 Tomcat6)
First I thought I would use StringBuilders, append the logs to them and a task would persist them into the database like every 2 minutes. Because I was worried about the out-of-the-box logging system's performance. Then I made some test. Especially with log4j.
首先,我想我会使用 StringBuilders,将日志附加到它们,然后一个任务会像每 2 分钟一样将它们持久化到数据库中。因为我担心开箱即用的日志系统的性能。然后我做了一些测试。特别是使用 log4j。
Here is my code:
这是我的代码:
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.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
I think this is a very common configuration for log4j. First I used log4j 1.2.14 then I realized there was a newer version, so I switched to 1.2.16
我认为这是 log4j 的一个非常常见的配置。首先我使用 log4j 1.2.14 然后我意识到有一个更新的版本,所以我切换到 1.2.16
Here are the figures (all in millisec)
这是数字(全部以毫秒为单位)
LoggerThread.threadsNumber = 10
LoggerThread.threadsNumber = 10
1.2.14: 4235, 4267, 4328, 4282
1.2.16: 2780, 2781, 2797, 2781
LoggerThread.threadsNumber = 100
LoggerThread.threadsNumber = 100
1.2.14: 41312, 41014, 42251
1.2.16: 25606, 25729, 25922
I think this is very fast. Don't forget that: in every cycle the run method not just log into the file, it has to concatenate strings (name + ": " + i)
, and check an if test (i == 9999)
.
我认为这是非常快的。不要忘记:在每个循环中,run 方法不仅会登录到文件中,还必须连接 strings(name + ": " + i)
并检查 if test (i == 9999)
。
When threadsNumber is 10, there are 100.000 loggings and if tests and concatenations. When it is 100, there are 1.000.000 loggings and if tests and concatenations. (I've read somewhere JVM uses StringBuilder's append for concatenation, not simple concatenation).
当threadsNumber 为10 时,有100.000 个日志记录以及if 测试和连接。当它是 100 时,有 1.000.000 个日志记录以及 if 测试和连接。(我在某处读到 JVM 使用 StringBuilder 的 append 进行连接,而不是简单的连接)。
Did I miss something? Am I doing something wrong? Did I forget any factor that could decrease the performance? If these figures are correct I think I don't have to worry about log4j's performance even if I heavily log, do I?
我错过了什么?难道我做错了什么?我是否忘记了任何可能降低性能的因素?如果这些数字是正确的,我想即使我大量登录也不必担心 log4j 的性能,是吗?
I've read that: "The typical cost of actually logging is about 100 to 300 microseconds." Is it correct? (log4J manual)
我读过:“实际记录的典型成本约为 100 到 300 微秒。” 这是正确的吗?( log4J 手册)
采纳答案by Péter T?r?k
Yes, Log4J is known to be fast, due to the conscious effort of its implementors. See also the section "Performance" at the end of this introduction to Log4J.
是的,由于其实现者的有意识的努力,众所周知 Log4J 速度很快。另请参阅Log4J 简介末尾的“性能”部分。
回答by unbeli
I don't have to worry about log4j's performance even if I heavily log
即使我大量登录,我也不必担心 log4j 的性能
Exactly. Do not optimize until your profiling results tell you to. There are cases, when logging performance is a bottleneck, but you need first to hit that case, then optimize for it.
确切地。在您的分析结果告诉您之前不要优化。在某些情况下,日志记录性能是瓶颈,但您需要首先解决该情况,然后对其进行优化。
回答by Romain Hippeau
Make sure you have a proper logging strategy. That means make sure you define what to log and have it separated into debug, trace, info, warning and error as well some others if you need them. Also make sure you give the ability to switch it on and off to enact performance/debugging as needed.
确保您有适当的日志记录策略。这意味着确保您定义要记录的内容并将其分为调试、跟踪、信息、警告和错误以及其他一些(如果需要)。还要确保您能够根据需要打开和关闭它以执行性能/调试。
Logging can have a significant impact on a heavily used site/app, Also logging too much gives you more information than you can sort through. Logging sometimes is the only post-incident debugging tool you have so make sure you make it count.
日志记录可能会对频繁使用的站点/应用程序产生重大影响,而且日志记录过多会为您提供比您可以整理的更多信息。有时,日志记录是您拥有的唯一事件后调试工具,因此请确保对其进行计数。
回答by Brian M. Carr
If performance is a concern, be sure to pay special attention to the pattern layout documentation and avoid expensive conversion characters such as C, F, L, and M. These require shenanigans to retrieve this info.
如果性能是一个问题,请务必特别注意模式布局文档并避免使用昂贵的转换字符,例如 C、F、L 和 M。这些需要恶作剧来检索此信息。
In place of C, use c and appropriately name your Logger objects when they are created. This means you can't inherit loggers from parent classes, but the inconvenience of redefining the logger is worth the increase to performance. F, L, and M don't have easy replacements for their functionality, but well worded log messages should be really easy to find in your source, so the need to specify the exact method, file, and line is diminished.
代替 C,使用 c 并在创建 Logger 对象时适当地命名它们。这意味着你不能从父类继承记录器,但重新定义记录器带来的不便值得提高性能。F、L 和 M 的功能没有简单的替代品,但是在您的源代码中应该很容易找到措辞良好的日志消息,因此无需指定确切的方法、文件和行。
Finally, avoid dynamic string concatenation in your log messages. When it is necessary to use concatenation, be sure to wrap the creation of that logging string in the appropriate checker method.
最后,避免日志消息中的动态字符串连接。当需要使用串联时,一定要在适当的检查器方法中包装该日志字符串的创建。
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!");
}
}
The isDebugEnabled() always runs in constant time. LOG.debug() itself essentially does a isDebugEnabled() check at the beginning, but the string passed as a parameter must be fully built before that check can happen, causing an unnecessary delay when debug level is turned off.
isDebugEnabled() 始终以恒定时间运行。LOG.debug() 本身本质上是在开始时进行 isDebugEnabled() 检查,但作为参数传递的字符串必须在该检查发生之前完全构建,当调试级别关闭时会导致不必要的延迟。
回答by Tobias P.
If performance is really a concern have a look for slf4j: http://www.slf4j.org/manual.html
如果性能真的是一个问题,请查看 slf4j:http://www.slf4j.org/manual.html
With their placeholder approach they are faster than log4j when you disabled logging those messages, because in log4j the string concatenation takes places independently the message is really needed. Slf4j only replaces the placeholder if this message will be really logged.
使用他们的占位符方法,当您禁用记录这些消息时,它们比 log4j 更快,因为在 log4j 中,字符串连接独立于消息真正需要的位置。如果此消息将被真正记录,则 Slf4j 仅替换占位符。
But you can do something like this in log4j:
但是你可以在 log4j 中做这样的事情:
if(l.isDebugEnabled()) l.debug("log entry: " + 7);
But i think it's a lot of boilerplate-code so i am using slf4j
但我认为这是很多样板代码,所以我使用的是 slf4j
回答by irreputable
the bottle neck should be the hard disk. your test shows roughly 1MB/s disk write speed, which is quite poor actually.
瓶颈应该是硬盘。您的测试显示大约 1MB/s 的磁盘写入速度,这实际上很差。
回答by Vadzim
It must be noted that log4j suffers from numerous locking pains under heavy concurrent use.
必须注意的是,在大量并发使用下,log4j 会遭受许多锁定的痛苦。
More details and some workaround in my another answer: Production settings file for log4j?
我的另一个答案中的更多详细信息和一些解决方法: log4j 的生产设置文件?