1

我正在寻找一种方法来在我的日志消息中包含某些信息,而不必总是将此信息显式添加到消息本身中。

我的梦想场景是任何日志消息,无论它发生在控制器、服务还是域类中,都将包含一些已定义的信息集(例如登录用户的用户名)。这将在程序员完全不必担心的情况下发生,只需执行 log.debug("some message") 即可自动执行此操作。

这个想法是以 JSON 格式输出日志,因此上面消息的结构可能看起来像这样:

{ timestamp: "20130130T12:32", message: "some message", user: "steve", request-id: "245692"... }

我可以创建一个 log4j 布局,它可以为我很好地格式化所有这些,但问题是我首先如何将数据放在那里。

所以我的第一个问题是:Grails 中有什么东西可以用作“request-id”吗?其背后的想法是为用户发起的任何“事务”提供一个请求 ID。因此,控制器中的日志消息将具有与作为结果被调用的域或服务类中的日志消息相同的请求 ID。

第二个问题:在用户发起的事务中,有没有办法在层(控制器/服务/域)之间“透明地”移动诸如此类的信息?如果需要,我可以在控制器中生成我自己的请求 ID,然后我可以获得用户名并将这两个放在地图中。但是我如何将该映射传输到任何服务/域类并传输到它们的记录器中,而不是将它作为参数传递(我不想这样做,因为这会乱扔代码)?

任何想法都将不胜感激,我应该注意我对 Grails 很陌生,所以请保持温柔;-)

4

1 回答 1

1

我在#grails IRC 频道上获得了正确的推动。

Log4J(或实际上是 SLF4J)有一个叫做 MDC(映射诊断上下文 - http://www.slf4j.org/manual.html#mdc)的东西,它本质上是一个线程本地映射。通过创建过滤器并将我需要的信息添加到 MDC,我可以将这些信息包含在该线程中执行的所有日志消息中。

问题仍然存在,是否存在“请求 uuid”之类的东西,或者我是否应该使用 UUID.randomUUID().toString() 生成一个。

例子:

添加过滤器以生成和存储requestId

def filters = {
   all(controller:'*', action:'*') {
      before = {
         MDC.put 'requestId', UUID.randomUUID().toString()
      }
   }
}

在 Config 中,添加%X{requestId}模式

log4j = {
  appenders {
      console name:'stdout', layout:pattern(conversionPattern: '%d{DATE} %X{requestId} %5p %c{1}:%L - %m%n')
于 2013-01-30T23:19:48.187 回答