Mal*_*lax 64 java logging log4j
有时当我看到我的日志代码时,我想知道我是否做得对.可能没有明确的答案,但我有以下问题:
图书馆课程
我有几个库类可能会记录一些INFO消息.致命错误报告为例外.目前我的类中有一个静态记录器实例,类名作为日志名称.(Log4j的:Logger.getLogger(MyClass.class))
这是正确的方法吗?也许这个库类的用户不希望我的实现发送任何消息,或者想要将它们重定向到特定于应用程序的日志.我应该允许用户从"外部世界"设置记录器吗?你如何处理这种情况?
一般日志
在某些应用程序中,我的类可能希望将日志消息写入未由类名称标识的特定日志.(即:) HTTP Request log这样做的最佳方法是什么?想到一个查找服务......
cle*_*tus 38
你的约定很标准,非常好(imho).
要注意的一件事是来自过多的无限制调试调用的内存碎片,因此,使用Log4J(以及大多数其他Java日志框架),您最终得到如下内容:
if (log.isDebugEnabled()) {
log.debug("...");
}
Run Code Online (Sandbox Code Playgroud)
因为构建该日志消息(您可能没有使用)可能很昂贵,特别是如果完成数千或数百万次.
你的INFO级别日志记录不应该太"健谈"(从你说的,听起来不是这样).INFO消息通常应该是有意义且重要的,例如启动和停止应用程序.如果遇到问题,您可能想知道的事情.当您确实遇到正在尝试诊断的问题时,调试/精细级别日志记录会更常用.调试/精细记录通常仅在需要时打开.信息通常始终在线.
如果有人不想从您的类中获取特定的INFO消息,他们当然可以自由地更改您的log4j配置以获取它们.Log4j在这个部门非常简单(而不是Java 1.4日志记录).
至于你的HTTP事情,我一般都没有发现这是Java日志记录的问题,因为通常一个类负责你感兴趣的内容,所以你只需要把它放在一个地方.在(我的经验很少见)当你想要看似不相关的类的常见日志消息时,只需添加一些可以轻松获取的令牌.
Sap*_*asu 10
以下是我在所有项目中遵循的指导方针,以确保良好的性能.我已经根据互联网上各种来源的输入来制定这套指导方针.
就像今天一样,我相信Log4j 2是迄今为止用于登录Java的最佳选择.
基准测试可在此处获得.为了获得最佳性能,我遵循的做法如下:
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)private static final Marker sqlMarker = MarkerManager.getMarker("SQL"); private void method1() { logger.debug(sqlMarker, "SELECT * FROM EMPLOYEE"); }
Run Code Online (Sandbox Code Playgroud)int i=5, j=10; logger.info("Sample output {}, {}", ()->i, ()->j);
不要使用字符串连接.使用参数化消息,如上所示
使用日志配置的动态重新加载,以便应用程序自动重新加载日志记录配置中的更改,而无需重新启动应用程序
不要使用printStackTrace()或System.out.println()
应用程序应在退出前关闭记录器:
Run Code Online (Sandbox Code Playgroud)LogManager.shutdown();
Run Code Online (Sandbox Code Playgroud)<?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>
Run Code Online (Sandbox Code Playgroud)<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>
在@cletus的回答中,他写到了问题
if (log.isDebugEnabled()) {
log.debug("val is " + value);
}
Run Code Online (Sandbox Code Playgroud)
这可以通过使用SL4J来克服.它提供格式化帮助
log.debug("val is {}", value);
Run Code Online (Sandbox Code Playgroud)
仅在级别为debug时才构造消息.
所以,现在,出于性能和稳定性的原因,建议使用SL4J及其伴随记录器Logback .
关于实例化记录器,我使用Eclipse Java模板设置记录器取得了一些成功:
private static Logger log = Logger.getLogger(${enclosing_type}.class);
Run Code Online (Sandbox Code Playgroud)
这样可以避免JVM在堆栈跟踪中出现问题,并且可以减少(通常可能)创建堆栈跟踪的开销.
使用这样的模板的好处是,如果要为记录器设置一致的标准,可以与团队共享.
看起来IntelliJ支持表示封闭类型名称的模板变量的相同概念.我没有看到在NetBeans中轻松实现这一目标的方法.
我可能是从某个地方偷来的,但它很好。
它降低了复制和 Pasti^h^h^h 重构时混淆记录器的风险,并且打字更少。
在你的代码中:
private final static Logger logger = LoggerFactory.make();
Run Code Online (Sandbox Code Playgroud)
...以及 LoggerFactory 中:
public static Logger make() {
Throwable t = new Throwable();
StackTraceElement directCaller = t.getStackTrace()[1];
return Logger.getLogger(directCaller.getClassName());
}
Run Code Online (Sandbox Code Playgroud)
(请注意,堆栈转储是在初始化期间完成的。堆栈跟踪可能不会被 JVM 优化掉,但实际上并不能保证)
我正在查看应用程序的日志级别,并且我目前正在检测一种模式:
private static final Logger logger = Logger.getLogger(Things.class)
public void bla() {
logger.debug("Starting " + ...)
// Do stuff
...
logger.debug("Situational")
// Algorithms
for(Thing t : things) {
logger.trace(...)
}
// Breaking happy things
if(things.isEmpty){
logger.warn("Things shouldn't be empty!")
}
// Catching things
try {
...
} catch(Exception e) {
logger.error("Something bad happened")
}
logger.info("Completed "+...)
}
Run Code Online (Sandbox Code Playgroud)
log4j2-file 定义了一个 socket-appender,带有一个故障转移文件-appender。还有一个控制台附加程序。有时我会在情况需要时使用 log4j2 标记。
认为一个额外的视角可能会有所帮助。