这个日志语句有什么问题?
What's wrong with this logging statement?
我最近在现有应用程序中偶然发现了以下几行日志记录代码。这段代码在很多方面对我来说都是完全错误的
Method method = ...;// passed in as parameter
//...
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
我想知道
- 这段代码有什么问题?
- 什么对性能影响最大?
- 编写这样的日志记录语句的最佳方法是什么?
(注意:如 {}
所示,它是一个 SLF4J 记录器,xxxxxxxx
是用于在代码库中标识此特殊日志语句的唯一字符串)
日志记录是应用程序中的交叉关注点。
所以对于一般情况,我使用 interceptor/aspect 模式来做到这一点。
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
String msg = String.format("some text, for: %s %s in thread %d %s",
className, methodName, id, name);
在当前记录器的有效级别之前不检查就进行所有这些计算是没有意义的,因为即使未写入日志也会应用它。
此外,如果需要并在附加程序的模式中指定,所有这些信息都可以由 API 记录器检索。
此外这个也没有效果:
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
它还在检查级别之前格式化字符串。
有了实际的代码,这样更好:
if (LOGGER.isDebugEnabled()){
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
}
但更稳健的解决方案是使用 appender 模式用线程 id、方法等装饰日志信息...
最后作为一般方法,如果当前级别的检查(这里:if (LOGGER.isDebugEnabled()){
)没有包含日志处理,例如:
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
使用 log 方法更有效,该方法采用设计时采用的 var args,而不是在您的示例中使用,因为它会破坏其目的。
通过这种方式,如果有效记录器级别不匹配,它可以节省计算:
LOGGER.debug("some text, for: {} {} in thread {} {}", className, methodName, id, name);
我最近在现有应用程序中偶然发现了以下几行日志记录代码。这段代码在很多方面对我来说都是完全错误的
Method method = ...;// passed in as parameter
//...
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
我想知道
- 这段代码有什么问题?
- 什么对性能影响最大?
- 编写这样的日志记录语句的最佳方法是什么?
(注意:如 {}
所示,它是一个 SLF4J 记录器,xxxxxxxx
是用于在代码库中标识此特殊日志语句的唯一字符串)
日志记录是应用程序中的交叉关注点。
所以对于一般情况,我使用 interceptor/aspect 模式来做到这一点。
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
String msg = String.format("some text, for: %s %s in thread %d %s",
className, methodName, id, name);
在当前记录器的有效级别之前不检查就进行所有这些计算是没有意义的,因为即使未写入日志也会应用它。
此外,如果需要并在附加程序的模式中指定,所有这些信息都可以由 API 记录器检索。
此外这个也没有效果:
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
它还在检查级别之前格式化字符串。
有了实际的代码,这样更好:
if (LOGGER.isDebugEnabled()){
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
long id = Thread.currentThread().getId();
String name = Thread.currentThread().getName();
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
}
但更稳健的解决方案是使用 appender 模式用线程 id、方法等装饰日志信息...
最后作为一般方法,如果当前级别的检查(这里:if (LOGGER.isDebugEnabled()){
)没有包含日志处理,例如:
String msg = String.format("some text, for: %s %s in thread %d %s", className, methodName, id, name);
LOGGER.debug("xxxxxxxx {}", msg);
使用 log 方法更有效,该方法采用设计时采用的 var args,而不是在您的示例中使用,因为它会破坏其目的。
通过这种方式,如果有效记录器级别不匹配,它可以节省计算:
LOGGER.debug("some text, for: {} {} in thread {} {}", className, methodName, id, name);