是否需要执行if(log.isDebugEnabled()){...}检查?

Oh *_*oon 42 java logging if-statement log4j

有没有必要做一个明确的if(log.isDebugEnabled()){...}检查?

我的意思是我看到一些帖子提到log.debug("something")在进行日志记录之前进行隐式调用以查看是否已启用调试模式日志记录.我错过了什么,或者在使用之前是否有中间步骤?

谢谢!

log.debug("ResultSet rs is retrieved from OracleTypes");
Run Code Online (Sandbox Code Playgroud)

VS

if(log.isDebugEnabled()){
     log.debug("ResultSet rs is retrieved from OracleTypes");
}
Run Code Online (Sandbox Code Playgroud)

编辑:写了这篇文章:http: //java.sg/whether-to-do-a-isdebugenabled-checking-before-printing-out-your-log-statement/

Fil*_*has 73

该声明:

if(log.isDebugEnabled()){
Run Code Online (Sandbox Code Playgroud)

仅用于性能原因.它的使用是可选的,因为它在内部由log方法调用.

但是现在你问这个检查是否是内部检查的,那我为什么要使用呢?这很简单:如果你记录的内容很简单:

log.debug("ResultSet rs is retrieved from OracleTypes");
Run Code Online (Sandbox Code Playgroud)

然后你不需要做任何检查.如果你使用append运算符(+)组成一个字符串来记录,如下所示:

log.debug("[" + System.getTimeInMillis() + "] ResultSet rs is retrieved from OracleTypes");
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您应该检查日志是否已启用,因为如果不是,即使没有创建日志,字符串组成也是如此.我必须提醒你,使用运算符"+"来连接字符串是非常低效的.

  • 字符串连接在内部创建了许多临时对象.如果您有许多这样的日志语句,即使日志被禁用,您也会失去性能. (3认同)

yng*_*ger 39

我知道这是旧的,但对于任何人来说都是这样......

如果使用SLF4J,则可以使用消息格式避免isDebugEnabled()调用.

例如,而不是:

Object entry = new SomeObject();
logger.debug("The entry is " + entry + ".");
Run Code Online (Sandbox Code Playgroud)

使用:

Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);
Run Code Online (Sandbox Code Playgroud)

除非启用调试,否则不会评估消息格式.

因此,对于简单的情况,您可以避免使用isDebugEnabled().

但是在构建其中一个参数可能很昂贵的情况下,您仍然希望使用isDebugEnabled()(即使使用SLF4J).

例如:

if (logger.isDebugEnabled()) {
    logger.debug("Here is the SQL: {}", sqlWrapper.buildSQL());  // assume buildSQL() is an expensive operation
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,除非实际启用了调试,否则您不希望评估buildSQL().

对于SLF4J,有一些关于使用它总是与选择性地使用它的争论.这真的归结为个人偏好.您可能希望在任何地方使用,以防止其他开发人员(在不知不觉中)将您的日志消息更改为更复杂/更昂贵的东西.

  • @yngwietiger 你是对的!该方法仍然被调用:`logger.debug("Hello World {}", test());` 将调用 `test()`,无论记录器级别如何 (2认同)
  • @yngwietiger 哦等等,你概述的场景 - 在日志消息中调用一个方法并不是一个正常的场景。是的,该方法将被调用,但对象不会对其 toString() 进行评估。这与文档所说的一致:`logger.debug("Hello World {}", test());` test 将被调用,但是 `logger.debug("Hello World {}", test);`其中 `test` 是一个对象,不会调用它的 `toString()`。是的 (2认同)

Boh*_*ian 8

Logger的最新版本简化了这一点,因此没有太大的区别.

最大的区别是你不必创建记录的东西 - 有时会有很多字符串添加.


Ash*_*hab 7

我通过执行代码中的检查与未执行检查来检查以下代码.有趣的是,如果在我们的代码中执行检查,执行了一百万次执行的4个日志语句,则额外需要400毫秒.我正在使用SLF4J 1.6.6.如果您能够承受每百万请求400毫秒的速度,则不需要检查.

    long startTime = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        if (logger.isTraceEnabled()) {
            logger.trace(request.getUserID());
            logger.trace(request.getEntitlementResource().getResourceString());
            logger.trace(request.getEntitlementResource().getActionString());
            logger.trace(request.getContextMap());
        }
    }
    long endTime = System.currentTimeMillis();
    logger.fatal("With Check Enabled : " + (endTime - startTime) + " ms");

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {

        logger.trace(request.getUserID());
        logger.trace(request.getEntitlementResource().getResourceString());
        logger.trace(request.getEntitlementResource().getActionString());
        logger.trace(request.getContextMap());

    }
    endTime = System.currentTimeMillis();
    logger.fatal("With Check Disabled : " + (endTime - startTime)  + " ms");
Run Code Online (Sandbox Code Playgroud)

---输出---

*2016-01-07 10:49:11,501 ERROR [:http-bio-8080-exec-3] [com.citi.cmb.entitlement.service.EntitlementServiceImpl] [] - 启用检查:661 ms

2016-01-07 10:49:57,141 ERROR [:http-bio-8080-exec-3] [com.citi.cmb.entitlement.service.EntitlementServiceImpl] [] - 禁用检查:1043 ms

  • 在第一个块中,`isTraceEnabled` 只检查了 4 条语句一次,实际上情况并非如此,每条语句 `isTraceEnabled` 都会被检查。如果您可以发布此更改的结果,那就太好了。 (2认同)