【问题标题】:logback: how to set logging level per thread?logback:如何设置每个线程的日志记录级别?
【发布时间】:2015-07-18 19:22:33
【问题描述】:

我有一个多线程 Java 应用程序,每个线程都是一个扩展基类的类,该基类扩展了 Thread。其中一个线程偶尔会为基类中的方法提供大量机器生成的数据,而其他线程只提供少量的人工输入数据。我想在比机器数据更高的日志级别上记录这些人工输入的消息,但由于基类是所有线程的一部分,我无法在代码中区分。

一种解决方案是通知扩展类中的基类登录到不同的级别,但是我必须将这些知识硬编码到应用程序中,这很难看。

我想做的是通过我的 logback.xml 配置“引导”它。

我写了一个小复制器:

package x.y.z;
import org.slf4j.*;

public class Quickie {
    static final Logger LOG = LoggerFactory.getLogger(Quickie.class);

    public static void main(String[] args) throws Exception {

        MyThread t1 = new MyThread("hi");
        MyThread t2 = new MyThread("bye"); 

        t1.start(); t2.start();
    }
}

class MyThread extends Thread {
    static final Logger LOG = LoggerFactory.getLogger(MyThread.class);

    public MyThread(final String name) { this.setName(name); }

    public void run() { logSomething(); }

    public void logSomething() {
        LOG.trace(getName()); LOG.error(getName());
    }
}

这是 logback 配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%date{HH:mm:ss} %-6level %-10([%thread]) %logger{1}.%method:%line %message%n</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>TRACE</level>
        </filter>
    </appender>

    <root level="TRACE">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

最重要的是,编码器模式是:

            <pattern>%date{HH:mm:ss} %-6level %-10([%thread]) %logger{1}.%method:%line %message%n</pattern>

因为这清楚地显示了线程:

11:16:09 TRACE  [bye]      c.t.k.t.MyThread.logSomething:24 bye
11:16:09 TRACE  [hi]       c.t.k.t.MyThread.logSomething:24 hi
11:16:09 ERROR  [bye]      c.t.k.t.MyThread.logSomething:24 bye
11:16:09 ERROR  [hi]       c.t.k.t.MyThread.logSomething:24 hi

...我想说应该有一种方法来配置我的 logback.xml 让“再见”线程只登录信息或更高版本,而“嗨”线程从跟踪或更高版本记录?我花了半天时间在谷歌上搜索和阅读 logback 文档,并尝试了 sifters 和 regex 过滤器以及许多其他示例,但显然它们都只是在传递信息。这意味着一种解决方案可能是在消息中出现一个神奇的字符串并将其过滤掉,但这也很丑陋。

那么,有没有一种方法可以在日志配置中控制每个线程的日志级别,而无需将“专用代码”注入应用程序?

【问题讨论】:

  • 这听起来是一个使用标记的好案例。

标签: java multithreading logback


【解决方案1】:

在这种情况下,我认为您需要使用阈值信息声明另一个附加程序和记录器。由于 appender 本身不知道将从哪个线程调用它。

【讨论】:

  • 但是 appender 模式中有一个 %thread 并且有效(请参阅我的问题中的模式和日志输出),所以它必须知道线程,对吗?这就是我的希望主要基于...
【解决方案2】:

我认为您可以为此目的使用 MDC 和 TurboFilter。

run() 方法中添加MDC.put() 的调用,如下所示:

public void run() {
    MDC.put("threadname", this.getName());
    logSomething();
}

如果您希望“再见”线程仅登录 info 或更高版本,而“hi”线程从 trace 或更高版本登录,则必须将 DynamicThresholdFilter 的定义添加到 logback.xml

<configuration>
  <turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
    <Key>threadname</Key>
    <!-- You can set default threshold as you like -->
    <DefaultThreshold>TRACE</DefaultThreshold>
    <MDCValueLevelPair>
      <value>bye</value>
      <level>info</level>
    </MDCValueLevelPair>
    <MDCValueLevelPair>
      <value>hi</value>
      <level>trace</level>
    </MDCValueLevelPair>
  </turboFilter>
  ......
</configuration>

【讨论】:

    猜你喜欢
    • 2016-11-27
    • 1970-01-01
    • 2023-03-23
    • 2011-12-11
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    相关资源
    最近更新 更多