以下是我在所有项目中遵循的一套指导方针,以确保良好的性能。我已经根据互联网上各种来源的输入形成了这套指南。
到今天为止,我相信 Log4j 2 是迄今为止登录 Java 的最佳选择。
基准可在此处获得。我为获得最佳性能而遵循的做法如下:
- 我目前避免使用 SLF4J,原因如下:
- 使用异步记录器执行所有常规记录以获得更好的性能
- 使用同步记录器将错误消息记录在单独的文件中,因为我们希望在错误消息发生时立即看到它
- 不要在常规日志中使用位置信息,例如文件名、类名、方法名、行号,因为为了派生这些信息,框架会拍摄堆栈的快照并遍历它。这会影响性能。因此,仅在错误日志中使用位置信息,而不在常规日志中使用
- 为了跟踪由单独线程处理的单个请求,请考虑使用线程上下文和随机 UUID,如此处所述
- 由于我们将错误记录在单独的文件中,因此将上下文信息也记录在错误日志中非常重要。例如,如果应用程序在处理文件时遇到错误,则在错误日志文件中打印文件名和正在处理的文件记录以及堆栈跟踪
- 日志文件应该是 grep-able 且易于理解的。例如,如果应用程序处理多个文件中的客户记录,则每个日志消息应如下所示:
12:01:00,127 INFO FILE_NAME=file1.txt - Processing starts
12:01:00,127 DEBUG FILE_NAME=file1.txt, CUSTOMER_ID=756
12:01:00,129 INFO FILE_NAME=file1.txt - Processing ends
- 使用 SQL 标记记录所有 SQL 语句,如下所示,并使用过滤器启用或禁用它:
private static final Marker sqlMarker =
MarkerManager.getMarker("SQL");
private void method1() {
logger.debug(sqlMarker, "SELECT * FROM EMPLOYEE");
}
- 使用 Java 8 Lambda 记录所有参数。当给定的日志级别被禁用时,这将使应用程序免于格式化消息:
int i=5, j=10;
logger.info("Sample output {}, {}", ()->i, ()->j);
不要使用字符串连接。使用如上所示的参数化消息
使用日志配置的动态重新加载,以便应用程序自动重新加载日志配置中的更改,而无需重新启动应用程序
不要使用printStackTrace()
或System.out.println()
应用程序应在退出前关闭记录器:
LogManager.shutdown();
- 最后,供大家参考,我使用如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorinterval="300" status="info" strict="true">
<Properties>
<Property name="filePath">${env:LOG_ROOT}/SAMPLE</Property>
<Property name="filename">${env:LOG_ROOT}/SAMPLE/sample
</Property>
<property name="logSize">10 MB</property>
</Properties>
<Appenders>
<RollingFile name="RollingFileRegular" fileName="${filename}.log"
filePattern="${filePath}/sample-%d{yyyy-dd-MM}-%i.log">
<Filters>
<MarkerFilter marker="SQL" onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<PatternLayout>
<Pattern>%d{HH:mm:ss,SSS} %m%n
</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy
interval="1" modulate="true" />
<SizeBasedTriggeringPolicy
size="${logSize}" />
</Policies>
</RollingFile>
<RollingFile name="RollingFileError"
fileName="${filename}_error.log"
filePattern="${filePath}/sample_error-%d{yyyy-dd-MM}-%i.log"
immediateFlush="true">
<PatternLayout>
<Pattern>%d{HH:mm:ss,SSS} %p %c{1.}[%L] [%t] %m%n
</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy
interval="1" modulate="true" />
<SizeBasedTriggeringPolicy
size="${logSize}" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<AsyncLogger name="com"
level="trace">
<AppenderRef ref="RollingFileRegular"/>
</AsyncLogger>
<Root includeLocation="true" level="trace">
<AppenderRef ref="RollingFileError" level="error" />
</Root>
</Loggers>
</Configuration>
- 所需的 Maven 依赖项在这里:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.6</version>
</dependency>
<!-- (Optional)To be used when working
with the applications using Log4j 1.x -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.8.1</version>
</dependency>