如何在所有执行上下文的播放框架日志中记录请求 ID

Posted

技术标签:

【中文标题】如何在所有执行上下文的播放框架日志中记录请求 ID【英文标题】:How to log request Id in play framework log across all execution context 【发布时间】:2016-07-27 19:49:39 【问题描述】:

我们有一个庞大的遗留代码,其中包含具有同步和异步操作的复杂流程。因此,我们需要在所有日志消息中记录特定请求的唯一 ID,其中执行的操作在不同的线程中运行,并且线程处于多个执行上下文中。

我尝试使用 MDC 并在 logger.xml 中指定 -%Xreq_id 以及使用自定义 akka 调度程序在下面提到的博客中给出的解决方案,但它不能在多个执行上下文中工作,而且它也不能可靠地工作在单个执行上下文中,有时它返回 req_id null。 (http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/)

由于复杂和庞大的代码库,不可能在每个函数调用中传递请求 ID。有什么方法可以实现这一点,而且改动最少?我们也需要播放框架生成的日志中的请求 ID。

【问题讨论】:

【参考方案1】:

我也有同样的需要,为了调试目的记录一些跟踪令牌。 Kamon 库已经有这个功能http://kamon.io/integrations/logback/trace-token-converter/.

在我的 Global.java 中:我在 onStart() 中执行 Kamon.start() 并在 onRequest() 中维护上下文。还要在日志模式中使用traceToken

public Action onRequest(Http.Request request, Method actionMethod) 
  TraceContext tx = Kamon.tracer().newContext("reqc", new Some<>(Utils.randStr(8)));
  Tracer.setCurrentContext(tx);
  Logger.info("Request: " + request.toString());
  Action x = super.onRequest(request, actionMethod);
  tx.finish();
  return x;

【讨论】:

但 onRequest() 不适用于 Play 中的所有执行上下文。根据我的理解,我说的对吗? onRequest() 仅在发出请求时可用。同样,在所有其他上下文中,您必须创建并完成 TraceContext【参考方案2】:

我们通过移动到单个执行器上下文解决了这个问题,play 2.5 也建议这样做。在这种情况下,mdc 上下文将起作用。

【讨论】:

所以你解决了,但是怎么解决的?因为这只是评论而不是解决方案! 在 application.conf 中你必须定义了不同的执行上下文。只是不要使用一个,我现在没有conf文件的副本。【参考方案3】:

您应该可以使用marker context 来完成这项工作。来自示例:

trait RequestMarkerContext 

  // Adding 'implicit request' enables implicit conversion chaining
  // See http://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html
  implicit def requestHeaderToMarkerContext(implicit request: RequestHeader): MarkerContext = 
    import net.logstash.logback.marker.LogstashMarker
    import net.logstash.logback.marker.Markers._

    val requestMarkers: LogstashMarker = append("host", request.host)
      .and(append("path", request.path))

    MarkerContext(requestMarkers)
  


然后

def asyncIndex = Action.async  implicit request =>
  Future 
    methodInOtherExecutionContext() // implicit conversion here
  (otherExecutionContext)


def methodInOtherExecutionContext()(implicit mc: MarkerContext): Result = 
  logger.debug("index: ") // same as above
  Ok("testing")

【讨论】:

以上是关于如何在所有执行上下文的播放框架日志中记录请求 ID的主要内容,如果未能解决你的问题,请参考以下文章

Java 基础学习总结(203)—— 生成唯一 ID 打印日志记录最佳实践

Java 基础学习总结(203)—— 生成唯一 ID 打印日志记录最佳实践

Java 基础学习总结(203)—— 生成唯一 ID 打印日志记录最佳实践

django 日志记录为每个请求全局设置上下文?

Laravel框架中如何使用事件记录SQL查询到日志

如何使用 JSON 格式将 lambda 请求 ID 记录到 AWS CloudWatch Api 网关日志组中?