<< [ lucene扩展 ] spellChecker原理分析 - MR-fox - 博客园 | 首页 | 5分钟开启Esper之旅 - Binhua Liu - 博客园 >>

log4j 日志性能优化

日志记录是大多数应用中的一项共同需求。但是日志记录不是没有坏处,我们需要付出性能上的损失。日志是一个I / O活动,并使用'同步'的代码,同时使用appender追加在单一的文件中写入。

 

无法摆脱的日志记录,但要得到最佳的性能,让我们看看,提高我的应用程序性能的最佳做法。

 

1.基本规则 - 通常我们所知道,但很多时间忽略了─

 

如果你正在做在你的日志象mylogString.append(“blah blah”).append(“few more blah blah”).append(“..”),先使用"if(logger.isDebugEnabled())"语句做个判断,如果您的应用程序配置为“Info”或更高的日志记录级别,这样会阻止字符串操作,

堆栈跟踪不应该打印超过一次。

尝试使用SLF4J(包装log4j)。它提供了一些很好的功能开箱。

生产环境设置日志记录级别为“警告”级别(如果可能的话),并以同样的方式设计自己的日志。它有助于保持日志文件体积小,对警告和错误更好的可见性。

2.不要使用“%C”,“%F”,“%M”,“%L”转换字符为的log4j.xml或log4j.properties定义文件日志记录模式。在这里查看官方的警告:

 

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html(生成调用者的位置信息是极其缓慢的,应该避免,除非执行速度是不是一个问题。)

3.使用日志缓冲 - 缓冲避免发送每个日志事件到日志文件,并会减少IO操作。

 

在下面的示例代码中,使用“Buffered IO” - > true“和BufferSize。然而,在较高的缓冲区大小设置下,要在日志文件中立即看到你的日志(特别是如果你使用“tail -f”看日志文件)有问题。其次,如果服务器崩溃,你可能会看不到仍处于缓冲内存日志记录,还没有刷新日志文件信息的最后一个重要的部分。

<appender name="mainAppender" class="org.apache.log4j.RollingFileAppender">

 <param name="File" value="../log/server.log" />

 <param name="Append" value="true" />

 <param name="MaxFileSize" value="10MB"/>

 <param name="MaxBackupIndex" value="20"/>

 <param name="ImmediateFlush" value="false" />

 <param name="BufferedIO" value="true" />

 <param name="BufferSize" value="16" /> <!-- In KB, Default is 8KB -->

 <layout class="org.apache.log4j.PatternLayout">

        <param name="ConversionPattern" value="%d %X{user}[%t] %-5p - %m%n" />

 </layout>

 </appender>

 

4.考虑使用'Asyn“记录日志 - 使用'ASYN”记录有巨大的性能提升。异步日志记录在后台线程中完成

 

<appender name="asyncAppender" class="org.apache.log4j.AsyncAppender"> 

 <param name="BufferSize" value="128" />

 <param name="Blocking" value="true" />

 <appender-ref ref="mainAppender" /> 

 </appender>

 

在上面的代码中三个重要的参数-

 

缓冲区大小:这又是一个需要在“性能”和“延时刷新日志数据'之间权衡。大的值有较高的的性能。

阻塞:意思是'如果缓冲区已满,仍在等待刷新,怎么做“。如果是“false”,日志appender将丢弃记录事件,直到缓冲区可用,提供了更好的性能。默认为“true”。这也是一个权衡。然而,'Asyn'的日志操作可以忽略main appender缓存的日志事件。

Appender-Ref:它采用最初定义“main Appender”(步骤2)做记录。然而,在“ASYN”记录场景,您可以忽略main appender缓冲日志事件的。请注意,“ASYN logger”缓冲基于“日志事件数量'但是'main logger”缓冲是基于日志的大小。

此外,更多的缓冲 ->刷新日志有更多的延迟​​。 (你可能错过服务器崩溃情况下的一些日志)

 

5.映射诊断上下文(MDC) - 虽然这个功能和性能没有直接关系的,但它让你的日志代码干净。 MDC使用ThreadLocal的存储来存储上下文方面的具体信息。 MDC可以用于记录像loged-in的用户名,事务ID,任何其它标识符来记录日志。

 

这真的有助于调试用户或交易的日志。这可通过跨类和方法的传递上下文的具体信息。

 

In your code - > MDC.put("userssion.getUser()); (import org.apache.log4j.MDC)

In Log4j.xml (or log4j.properties), set pattern layout with %X: 

 <param name="ConversionPattern" value="%d %X{user}[%t] %-5p - %m%n" />

 

2012-11-02 12:12:04,586 [user: 0x3c5c84b3][pool-7-thread-182] DEBUG .......

2012-11-02 12:12:04,586 [user: 0x4c678c66][pool-7-thread-182] DEBUG .......

 

6.多个记录器支持 - 如果在你的应用程序使用多个记录器,如果你得到重复的日志条目,请考虑加上'additivity=talse'属性。

<logger name="me.prettyprint" additivity="false">

 <level value="error" />

 <appender-ref ref="cassandraAppender" />

</logger>

 

7.可以考虑压缩日志文件,如果担心存储和文件传输。

<appender...>

 <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">

 <param name="FileNamePattern" value="server.log.%d{yyyy-MM}**.gz**"/>

 </rollingPolicy>

</appender>

http://logging.apache.org/log4j/companions/extras/apidocs/org/apache/log4j/rolling/TimeBasedRollingPolicy.html

 

8.有时需要服务器切换到不同的日志级别(如“警告”,以“调试”),但不希望修改服务器。我们可以通过编程配置我们的日志级别,公开为JMX服务:

public void setLogLevel(String loggerName, String newLevel) throws IllegalArgumentException {

 final Level level = Level.toLevel(newLevel);

 if (!newLevel.equalsIgnoreCase(level.toString())) {

 throw new IllegalArgumentException("Invalid log level");

 }

final Logger logger = Logger.getLogger(loggerName);

 if ((logger == null) || (logger.getLevel() == null)) {

 throw new IllegalArgumentException("Logger does not exist."); 

 }

logger.setLevel(level);

}

9.可以改变日志到ASYN/ SYN,缓冲/非缓冲模式。欲了解更多详情请参阅log4j的API。为了演示,我给一个片段:

// 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);

 

标签 :



发表评论 发送引用通报