与许多log4j用户一样,我们经常进行调试级别日志记录,评估成本很高。因此,我们使用以下代码保护这些案例:
if( _logger.isDebugEnabled )
_logger.debug("Interesting, my foojes are goofed up: " + getFullDetails())
然而,这比普通的_logger.debug调用更难,有时程序员没有意识到评估可能会很昂贵。
编写一个带有编译jar的程序并使用isDebugEnabled检查保护所有_logger.debug调用似乎应该相当简单。我们可能愿意接受在所有情况下检查isDebugEnabled的额外开销。
有没有人尝试过这种方法,或者对jar进行类似的后期处理?
答案 0 :(得分:4)
我没有考虑修改jar,而是使用Bytecode Instrumentation搜索解决方案。问题是识别要包含在.isDebugEnabled()
内的代码的那些部分 - 您必须识别仅用于log4j调用的对象。
答案 1 :(得分:2)
你看过AspectJ了吗?这支持使用字节码编织的方面,并且可以拦截into a previously compiled .jar file。
答案 2 :(得分:1)
我相信一个好的解决方案就是代码效率很高。
考虑不推荐使用log4j。它的作者本身保留原样,以避免破坏兼容性,但他创建了一个新的SLF4J(http://www.slf4j.org/)。根据commons-logging / log4j的区别,他提供了一个外观和一个实现,但没有每个的缺陷......
我相信,在这个新的日志记录工具中,您可以将Object参数发送到日志记录,并在转换Objects(到String或其他)之前评估级别。我们的想法是使用格式字符串和参数。
我们的代码不使用slf4j,但是我们有实用的方法就是这样。 它的编码大致如下(来自记忆):
public enum LogLevel {
FATAL, ERROR, WARNING, INFO, DEBUG;
public void log(Logger logger, String format, Object... parameters) {
if (isEnabled(logger)) {
logImpl(logger, String.format(format, parameters));
}
}
public boolean isEnabled(Logger logger) {
switch(this) {
case WARNING : return logger.isWarningEnabled();
case INFO : return logger.isInfoEnabled();
case DEBUG : return logger.isDebugEnabled();
default: return true;
}
}
private void logImpl(Logger logger, String message) {
switch(this) {
case WARNING : logger.warn(message);
// other cases
}
}
}
用作:
public void myMethod(Object param) {
LogLevel.WARNING.log(LOGGER, "What is my message ....", "myMethod", param);
}
更新:如果您需要在日志中调用方法...
一种可能性是使用toString
方法。如果您的日志记录是“技术性”,这是合适的,并且在调试时也会使用。
如果您的日志记录功能更强(不针对开发者),我建议定义一个接口(在这种情况下功能合理,因此提供意义很有用) :
public interface Detailable { // the name could also suggest logging?
String getFullDetails();
}
在任何需要作为日志记录对象传递的对象中实现该接口,并使用复杂的计算来构建日志。