【问题标题】:How to change log level only for current thread with Logback如何仅使用 Logback 更改当前线程的日志级别
【发布时间】:2017-08-31 16:18:50
【问题描述】:

在 Logback 中,可以使用 setLevel() 方法更改 logger 的日志级别。 但是在 Logback 中,由于 logger 是单例的,所以 setLevel() 方法的调用会影响到所有其他使用相同 logger 的线程。

现在我有一个在这样的网络应用程序中使用的类:

class FooService {
    private void insertRecord(Foo foo) {
        // insert one record to DB
    }

    public void insertOne(Foo foo) {
        insertRecord(foo);
    }

    public void insertMany(List<Foo> foos) {
        // I want to stop logging here
        for (Foo foo: foos) {
            insertRecord(foo);
        }
        // I want to resume logging here
    }
}

在 Spring ApplicationConfig.xml 中:

<bean id="traceAdvice"
  class="org.springframework.aop.interceptor.CustomizableTraceInterceptor">
  <property name="enterMessage" 
    value="Entering $[targetClassShortName].$[methodName]($[argumentTypes])[$[arguments]]" />
  <property name="exitMessage" 
    value="Exiting  $[targetClassShortName].$[methodName] with return value $[returnValue], took $[invocationTime]ms" />
  <property name="exceptionMessage" 
    value="Exception thrown in $[targetClassShortName].$[methodName] : $[exception]" />
</bean>

<aop:config>
  <aop:pointcut id="pointcut-service" 
    expression="execution(* my.app.service..*Service.*(..))" />
  <aop:advisor advice-ref="traceAdvice" pointcut-ref="pointcut-service" />
</aop:config>

我想记录 insertOne 方法对 insertRecord 的调用。另一方面,在 insertMany 方法中,我想在循环之前停止记录(因为它可能会输出大量日志),并在循环之后恢复记录。 但是如果你在循环之前调用 setLevel() ,日志级别的变化会影响到其他线程中使用的其他记录器。在这种情况下,我认为您会在其他线程上获得不足的日志。

我的问题是:如何仅为当前线程中使用的记录器更改日志级别?

【问题讨论】:

  • 你可以为你的包或者你的类定义一个特定的 appender
  • 当然你可以为类FooService定义额外的appender,但是如果有两个或更多线程同时执行FooService,所有线程都会受到setLevel()的影响。这对我来说是不受欢迎的结果。
  • 您可以为它们设置两个不同的记录器。

标签: java logging logback


【解决方案1】:

我找到了解决方案。为此,您可以使用 MDC 和 TurboFilter。 MDC 是线程本地的,更改为 MDC 不会影响其他线程。

例如,如果要停止所有日志记录活动,则必须在 logback.xml 中添加 MDCFilter 的定义(注意 &lt;turboFilter&gt; 标签不能是 &lt;appender&gt; 标签的子标签,而应该是&lt;configuration&gt; 标签的孩子):

<configuration>
    <turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
      <MDCKey>tracing</MDCKey>
      <Value>off</Value>
      <OnMatch>DENY</OnMatch>
    </turboFilter>
    ......
</configuration>

您可以像这样通过向 MDC 放置/删除键和值来打开/关闭日志记录(请注意,您应该考虑实际使用中的异常):

class FooService {
    private void insertRecord(Foo foo) {
        // insert one record to DB
    }

    public void insertOne(Foo foo) {
        insertRecord(foo);
    }

    public void insertMany(List<Foo> foos) {
        // I want to stop logging here
        MDC.put("tracing", "off");
        for (Foo foo: foos) {
            insertRecord(foo);
        }
        // I want to resume logging here
        MDC.remove("tracing");
    }
}

或者,如果您想停止 TRACE/DEBUG/INFO/WARN 日志但保持 ERROR 日志处于活动状态,您可以使用 DynamicThresholdFilter:

<configuration>
    <turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
      <Key>tracing</Key>
      <DefaultThreshold>TRACE</DefaultThreshold>
      <MDCValueLevelPair>
        <value>off</value>
        <level>ERROR</level>
      </MDCValueLevelPair>
    </turboFilter>
    ......
</configuration>

【讨论】:

  • DynamicThresholdFilter 正是我所需要的,谢谢!
猜你喜欢
  • 1970-01-01
  • 2020-08-17
  • 2015-11-25
  • 2015-07-18
  • 2017-03-26
  • 2019-01-11
  • 2012-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多