当前位置: 首页 > 知识库问答 >
问题:

为什么(在某些情况下)logback调用toString()即使日志级别被禁用?

长孙景天
2023-03-14

我们最近在系统中遇到了一个性能问题,Logback调用了toString(),尽管指定的日志级别(DEBUG)没有为该特定的日志记录程序启用。当然,现在还有一个额外的问题是我们的toString()方法非常占用CPU,但logback的行为非常出乎意料。给定以下简单的测试案例,日志级别为mypkg。LogTest2未指定(默认),我看到toString()调用了两次,但没有打印日志消息(注意:针对logback-经典-0.9.29和logback-核心-0.9.29的链接)。

package mypkg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogTest2 {
   private static Logger ROOT_LOGGER = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
   private static Logger CLASS_LOGGER = LoggerFactory.getLogger(LogTest2.class);

   public static void main(String[] args){
      LogTest2 obj = new LogTest2();
   }
   public LogTest2() {
      if (CLASS_LOGGER.isDebugEnabled()) {
         ROOT_LOGGER.info("A CLASS_LOGGER debug guarded ROOT_LOGGER info message: {}", this);
         CLASS_LOGGER.debug("A class logger debug message: {}", this);
      }
   }
   public String toString() {
      System.out.println("================= LogTest2 toString invoked.");
      return "{LogTest2}";
   }
}

上述程序的输出:

================= LogTest2 toString invoked.
================= LogTest2 toString invoked.

为了完整起见,这里是回溯。我正在使用的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" debug="true">
  <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    <encoder><pattern>%c -> %msg%n</pattern></encoder>
  </appender>

  <!--  
  <logger name="mypkg" level="debug">  <appender-ref ref="stdout" />  </logger>
  -->
</configuration>

如果我更新了上面的日志。要取消对“mypkg”记录器的注释,输出会发生更改,但仍会额外调用toString()

================= LogTest2 toString invoked.
================= LogTest2 toString invoked.
mypkg.LogTest2 -> A class logger debug message: {LogTest2}

这与我对slf4j和logback日志应该如何工作的理解背道而驰。有人能帮我理解吗?这是错误还是预期的行为(为什么)?

共有1个答案

翁文康
2023-03-14

根记录器是在调试级别下创建的。创建子记录器时,其有效日志记录级别设置为其父记录器的有效日志记录级别。另外,isDebugEnabled()检查记录器(一个int值)的有效记录级别是否为

在没有声明记录器的示例中,它也没有任何附加器。消息已被构造,但没有登录的位置。因此,虽然调试级别确实得到了满足,但它不会记录任何地方。

在较新版本的logback中,日志消息的构造似乎是在检查appender之后完成的。

 类似资料:
  • 我最近将应用程序从log4j更改为logback/slf4j。一切都工作得很好,但我想实现一些具体的东西。 我正在开发的应用程序是一个web应用程序。在我们的生产环境中,日志级别是on info。不时有票进来让我们的服务团队处理。如果我们的服务团队在复制票据时,他们可以将日志级别放在跟踪上,只用于他们的测试请求,那就太好了。这样,日志文件就不会随着当时所有其他请求的到来而被修改。 我们已经使用标头

  • 问题内容: 说我有一个清单。在什么情况下被称为? 我基本上理解了文档,但是我也想看到一个示例来毫无疑问地阐明其用法。 问题答案: 当Python尝试将两个对象相乘时,它首先尝试调用左侧对象的方法。如果左对象没有方法(或者该方法返回,表明它不适用于所讨论的右操作数),则Python希望知道右对象是否可以进行乘法。如果右操作数与左操作数的类型相同,Python就会知道它不能,因为如果左对象不能做到这一

  • 我可以看到jconsole上的一些方法被禁用了。 下面是的屏幕截图 这些MBean方法的javadocs没有指定关于可访问性部分的任何内容。 我认为这是一个安全功能,但我不能得到一个具体的答案。 这个问题的第二个显而易见的部分是如何创建自定义MBean实现,该实现可以在JConsole上选择性地禁用。 以下是系统配置: JConsole版本“1.7.0-B147” Java(TM)SE运行时环境(

  • 问题内容: 为什么 工作,但是 不是吗 问题答案: 为了理解这一点,让我们考虑一下编译器在两种可能性下每个步骤所做的事情。让我们开始: 编译器将‘4’转换为int。所以变成 然后编译器变成 ch是一个字符,编译器可以将54转换为字符,因为它可以证明转换没有损失。 现在让我们考虑第二个版本: ch在编译时没有已知值。因此,这成为 现在,编译器无法证明此(int)的结果在char范围内可存储。因此它

  • 我应该何时使用低于日志级别?如果有任何例子,那将是伟大的。 跟踪与调试 警告 vs 错误 vs 致命 警告Vs错误VS致命 我是否需要首先在我的应用程序代码中使用FATAL? 迄今为止,在我参与的项目中,我从未在任何代码中看到致命的日志记录。 我读过,如果FATAL程序将结束。如果是这种情况,我想知道我的日志语句将如何执行。 此外,我认为在内存分配的情况下不能使用FATAL,因为JVM会抛出内存溢

  • 我正在测试一些东西,遇到了一个奇怪的情况,当我有一个断点时,IntelliJ没有调试我的代码,如图1所示。但是当我移动断点时,工作正常。 代码: 当我在这里有我的调试点时(见图),这不起作用并给出以下错误: 错误: 连接到目标虚拟机,地址:“127.0.0.1:59776”,传输:“socket”OpenJDK 64位服务器虚拟机警告:共享仅支持引导加载程序类,因为已附加引导类路径,与目标虚拟机断