【问题标题】:Pass context to async Logger将上下文传递给异步 Logger
【发布时间】:2017-03-28 01:25:04
【问题描述】:

我正在尝试记录来自 http 客户端的原始请求/响应。 我正在关注这些 logging instructions 中的 log4j2 配置。

HttpAsync 客户端依赖:- httpasyncclient(版本 4.1.1)

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
    <RollingRandomAccessFile name="app-log" fileName="${log.path}/app.log"
                             filePattern="${log.path}/app-%d{yyyy-MM-dd}.gz">
        <PatternLayout>
            <pattern>[%-5level] [%X{uuid}] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n</pattern>
        </PatternLayout>
        <Policies>
            <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
        </Policies>
    </RollingRandomAccessFile>
</Appenders>
<Loggers>
    <AsyncLogger name="org.apache.http.impl.conn.Wire" level="debug">
        <AppenderRef ref="app-log"/>
    </AsyncLogger>
    <AsyncRoot level="debug" includeLocation="true">
        <AppenderRef ref="app-log"/>
    </AsyncRoot>
</Loggers>
</Configuration>

打印正常,但线程上下文没有传递到线路记录器。

示例:-

// with uuid, output of logger.debug(ThreadContext.getImmutableContext().toString());

[DEBUG] [c48b97f7-0094-44af-82af-3d6b43d76014] 2016-11-14 17:06:03.408 [http-bio-8080-exec-1] OutboundRequestHandler - {uuid=c48b97f7-0094-44af-82af-3d6b43d76014}

// without uuid
[DEBUG] [] 2016-11-14 17:06:03.440 [I/O dispatcher 1] headers - http-outgoing-0 >> POST /abcd.json HTTP/1.1
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Content-Length: 2
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Content-Type: text/plain; charset=ISO-8859-1
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Host: 127.0.0.1:80
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> Connection: Keep-Alive
[DEBUG] [] 2016-11-14 17:06:03.441 [I/O dispatcher 1] headers - http-outgoing-0 >> User-Agent: Apache-HttpAsyncClient/4.1.1 (Java/1.8.0_92)

如何将 ThreadContext 传递给记录器?

谢谢。

【问题讨论】:

    标签: java log4j2 apache-httpasyncclient threadcontext


    【解决方案1】:

    v2.13.2 开始,建议创建ContextDataProvider 而不是ContextDataInjector

    ContextDataProvider(在 Log4j 2.13.2 中引入)是一个接口,应用程序和库可以用来将额外的键值对注入到 LogEvent 的上下文数据中。 Log4j 的 ThreadContextDataInjector 使用 java.util.ServiceLoader 来定位和加载 ContextDataProvider 实例。 Log4j 本身使用 org.apache.logging.log4j.core.impl.ThreadContextDataProvider 将 ThreadContextData 添加到 LogEvent。自定义实现应实现 org.apache.logging.log4j.core.util.ContextDataProvider 接口,并通过在名为 META-INF/services/org.apache.logging.log4j.core 的文件中定义实现类将其声明为服务。 util.ContextDataProvider。

    【讨论】:

      【解决方案2】:

      我不确定这在 2019 年的相关性如何,因为提问者肯定会转向其他事情。但它仍然存在:

      在 log4j2 中,我们必须使用 ThreadContext.put 而不是用于 log4j 的 MDC.put。这将完美地记录所有内容。休息一切都保持不变

      【讨论】:

      • 我认为 OP 知道 log4j 1.2 和 log4j 2 之间的区别,因为配置使用 log4j 2 语法并且标题提到了异步记录器。问题是关于如何将 ThreadContext 信息传递给工作线程的高级用例......
      • 我刚刚实现了这个并且使用 threadContext.put 对我来说工作正常。
      【解决方案3】:

      由于设置 UUID 的线程 (http-bio-8080-exec-1) 与应用程序中执行日志记录的线程 (I/O 调度程序 1) 不同,因此它们具有不同的 ThreadContext 映射和第二个线程看不到第一个线程在其地图中放置的内容。

      从 log4j 2.7 开始,可以创建一个custom context data injector,它可以从 ThreadLocal 映射以外的其他地方获取上下文数据(因为这本质上就是 ThreadContext)。

      这确实意味着您需要创建一个自定义外观,类似于 log4j 的 ThreadContext,您可以将键值对放入某些数据结构中。我不熟悉 AsyncHttpClient,但我找不到允许不同线程共享与同一会话关联的数据的“上下文”概念。

      您的自定义 context injector implementation 将拍摄键值对的快照并将其注入到每条日志消息的 LogEvent 中。

      【讨论】:

      • 如何定义键或值的范围。例如,http-bio-8080-exec-1 线程在传入请求拦截时会创建 uuid 并添加到 MDC,也会在写入响应之前在过滤器中清除。现在所有正在执行由该线程(aync 模型)提交的任务的线程都应该在记录器中记录 uuid。自定义数据注入器将如何提供帮助。(上述场景的更通用用例)不适用于任何其他场景任务。
      猜你喜欢
      • 2019-05-08
      • 1970-01-01
      • 2020-06-25
      • 1970-01-01
      • 2020-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多