当我们打开或关闭某些日志位置时,log4j 实际上在做什么?

发布于 2024-08-20 10:10:49 字数 224 浏览 2 评论 0原文

我们知道我们可以通过其属性/配置文件配置 log4j 以关闭特定位置(Java 中的类或包)的日志。我的问题如下:

  1. log4j 实际上对这些标志做了什么?
  2. log4j 中的日志语句是否仍然被调用,但只是因为该标志而没有被写入文件或控制台?那么仍然有性能影响吗?
  3. 是否像C++中的#ifdef一样在编译时生效然后可以限制性能影响?

谢谢,

We know we can config log4j to turn off log on specific places (class or package in Java) via its properties/configuration file. My questions are followed:

  1. what's log4j actually doing for those flags?
  2. is the log statement in log4j still called but just not being written to file or console because of that flag? so still have performance impact?
  3. is it like #ifdef in C++ which take effect at compile time then can limit the performance impact?

thanks,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拥有 2024-08-27 10:10:49

是的,日志语句仍然会被执行。这就是为什么首先检查日志级别是一个很好的模式:类似这样,

if (log.isInfoEnabled()) {
    log.info("My big long info string: " + someMessage);
}

当日志级别不支持 INFO 语句时,这是为了防止为信息 String 重新分配空间。

它与 #ifdef 不同 - #ifdef 是编译器指令,而 Log4J 配置是在运行时处理的。

编辑:我讨厌由于无知而被降级,所以这里有一篇文章支持我的答案。

来自http://surguy.net/articles/removing-log-messages.xml

在 Log4J 中,如果您在以下位置记录消息
DEBUG级别,以及当前的Appender
设置为仅记录 INFO 消息
级别及以上,则该消息将
不显示。性能
调用 log 方法的惩罚
本身是最小的——几纳秒。
然而,可能需要更长的时间
评估日志的参数
方法。例如:

logger.debug("大对象是
“+largeObject.toString());

评估largeObject.toString()可能会
慢一点,之前就评估过了
对记录器的调用,因此记录器
无法阻止对其进行评估,
即使它不会被使用。

编辑 2:来自 log4j 手册本身 (http://logging .apache.org/log4j/1.2/manual.html):

用户应该注意以下性能问题。

  1. 关闭日志记录时的日志记录性能。
    当完全关闭日志记录或仅关闭一组级别的日志记录时,日志请求的成本包括方法调用加上整数比较。在 233 MHz Pentium II 机器上,此成本通常在 5 到 50 纳秒范围内。

    但是,方法调用涉及参数构造的“隐藏”成本。

    例如,对于一些记录猫,写作,

     logger.debug("条目编号:" + i + " is " + String.valueOf(entry[i]));
    

    会产生构造消息参数的成本,即将整数i和entry[i]转换为字符串,并连接中间字符串,无论消息是否会被记录。参数构造的成本可能相当高,并且取决于所涉及参数的大小。

    为了避免参数构造成本,请编写:

    if(logger.isDebugEnabled() {
      logger.debug("条目编号:" + i + " is " + String.valueOf(entry[i]));
    }
    

    如果禁用调试,这不会产生参数构造的成本。另一方面,如果记录器启用了调试,则评估记录器是否启用的成本将增加两倍:一次在 debugEnabled 中,一次在调试中。这是一个微不足道的开销,因为评估记录器大约需要实际记录时间的 1%。

Yes, the log statements will still be executed. This is why it's a good pattern to check the log level first: something like

if (log.isInfoEnabled()) {
    log.info("My big long info string: " + someMessage);
}

This is to keep from reallocating space for the info String when the log level does not support INFO statements.

It's not anything like #ifdef - #ifdef is a compiler directive, whereas Log4J configurations are processed at runtime.

Edit: I hate getting downmodded due to ignorance, so here is one article backing up my answer.

From http://surguy.net/articles/removing-log-messages.xml:

In Log4J, if you log a message at
DEBUG level, and the current Appender
is set to only log messages of INFO
level and above, then the message will
not be displayed. The performance
penalty for calling the log method
itself is minimal - a few nanoseconds.
However, it may take longer to
evaluate the arguments to the log
method. For example:

logger.debug("The large object is
"+largeObject.toString());

Evaluating largeObject.toString() may
be slow, and it is evaluated before
the call to the logger, so the logger
cannot prevent it being evaluated,
even though it will not be used.

Edit 2: from the log4j manual itself (http://logging.apache.org/log4j/1.2/manual.html):

The user should be aware of the following performance issues.

  1. Logging performance when logging is turned off.
    When logging is turned off entirely or just for a set of levels, the cost of a log request consists of a method invocation plus an integer comparison. On a 233 MHz Pentium II machine this cost is typically in the 5 to 50 nanosecond range.

    However, The method invocation involves the "hidden" cost of parameter construction.

    For example, for some logger cat, writing,

     logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
    

    incurs the cost of constructing the message parameter, i.e. converting both integer i and entry[i] to a String, and concatenating intermediate strings, regardless of whether the message will be logged or not. This cost of parameter construction can be quite high and it depends on the size of the parameters involved.

    To avoid the parameter construction cost write:

    if(logger.isDebugEnabled() {
      logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
    }
    

    This will not incur the cost of parameter construction if debugging is disabled. On the other hand, if the logger is debug-enabled, it will incur twice the cost of evaluating whether the logger is enabled or not: once in debugEnabled and once in debug. This is an insignificant overhead because evaluating a logger takes about 1% of the time it takes to actually log.

辞慾 2024-08-27 10:10:49

我运行了一个简单的基准测试来测试。

    for (int j = 0; j < 5; j++) {
        long t1 = System.nanoTime() / 1000000;
        int iterations = 1000000;
        for (int i = 0; i < iterations; i++) {
            int test = i % 10;
            log.debug("Test " + i + " has value " + test);
        }
        long t2 = System.nanoTime() / 1000000;
        log.info("elapsed time: " + (t2 - t1));

        long t3 = System.nanoTime() / 1000000;
        for (int i = 0; i < iterations; i++) {
            int test = i % 10;
            if (log.isDebugEnabled()) {
                log.debug("Test " + i + " has value " + test);
            }
        }
        long t4 = System.nanoTime() / 1000000;
        log.info("elapsed time 2: " + (t4 - t3));
    }

elapsed time: 539
elapsed time 2: 17
elapsed time: 450
elapsed time 2: 18
elapsed time: 454
elapsed time 2: 19
elapsed time: 454
elapsed time 2: 17
elapsed time: 450
elapsed time 2: 19

对于 1.6.0_18,这让我感到惊讶,因为我本以为内联会阻止这种情况。也许具有转义分析功能的 Java 7 会。

然而,我仍然不会将调试语句包装在 if 子句中,除非半微秒数量级的时间改进变得很重要!

I ran a simple benchmark to test.

    for (int j = 0; j < 5; j++) {
        long t1 = System.nanoTime() / 1000000;
        int iterations = 1000000;
        for (int i = 0; i < iterations; i++) {
            int test = i % 10;
            log.debug("Test " + i + " has value " + test);
        }
        long t2 = System.nanoTime() / 1000000;
        log.info("elapsed time: " + (t2 - t1));

        long t3 = System.nanoTime() / 1000000;
        for (int i = 0; i < iterations; i++) {
            int test = i % 10;
            if (log.isDebugEnabled()) {
                log.debug("Test " + i + " has value " + test);
            }
        }
        long t4 = System.nanoTime() / 1000000;
        log.info("elapsed time 2: " + (t4 - t3));
    }

elapsed time: 539
elapsed time 2: 17
elapsed time: 450
elapsed time 2: 18
elapsed time: 454
elapsed time 2: 19
elapsed time: 454
elapsed time 2: 17
elapsed time: 450
elapsed time 2: 19

With 1.6.0_18, which surprised me as I would have thought the inlining would have prevented this. Maybe Java 7 with escape analysis will.

However I still wouldn't wrap debug statements in an if clause unless time improvements of the order of half a microsecond get to be important!

明媚如初 2024-08-27 10:10:49
  1. log4j 将处理日志语句,并检查是否在特定日志记录级别启用了特定记录器。如果不是,则不会记录该语句。

  2. 这些检查比实际写入磁盘(或控制台)要便宜得多,但它们仍然有影响。

  3. 不,java没有#ifdef这样的概念(无论如何,开箱即用,有java预编译器)

  1. log4j will process the log statement, and check to see if the particular logger is enabled at the particular logging level. If it is not, then the statement will not be logged.

  2. These checks are significantly less expensive than the actual writing to disk (or console), but they still have an impact.

  3. no, java has no such concept as #ifdef (out of the box anyway, there are java precompilers out there)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文