&引用;透明的;将请求/事务ID注入Grails中日志消息的方法

&引用;透明的;将请求/事务ID注入Grails中日志消息的方法,grails,grails-2.0,Grails,Grails 2.0,我正在寻找一种在日志消息中包含某些信息的方法,而不必总是显式地将这些信息添加到消息本身 我梦想的场景是,任何日志消息,无论它发生在控制器、服务或域类中,都将包含一些已定义的信息集(例如登录用户的用户名)。这一点程序员根本不必担心,只要做一个log.debug(“一些消息”)就会自动完成 我们的想法是以JSON格式输出日志,这样上面消息的结构可能会如下所示: { timestamp: "20130130T12:32", message: "some message", user: "steve",

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

我梦想的场景是,任何日志消息,无论它发生在控制器、服务或域类中,都将包含一些已定义的信息集(例如登录用户的用户名)。这一点程序员根本不必担心,只要做一个log.debug(“一些消息”)就会自动完成

我们的想法是以JSON格式输出日志,这样上面消息的结构可能会如下所示:

{ timestamp: "20130130T12:32", message: "some message", user: "steve", request-id: "245692"... }
我可以创建一个log4j布局,为我很好地格式化所有这些内容,但问题是我首先如何将数据放在那里

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

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


如果您有任何想法,我都将不胜感激,而且我应该注意到我对Grails还比较陌生,所以请您保持温和;-)

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

Log4J(或者实际上是SLF4J)有一个称为MDC(Mapped Diagnostic Context-)的东西,它本质上是一个线程本地映射。通过创建一个过滤器并向MDC添加所需的信息,我可以将此信息包含在该线程中执行的所有日志消息中

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

例如:

添加筛选器以生成和存储
请求ID

def filters = {
   all(controller:'*', action:'*') {
      before = {
         MDC.put 'requestId', UUID.randomUUID().toString()
      }
   }
}
在配置中,在模式中添加
%X{requestId}

log4j = {
  appenders {
      console name:'stdout', layout:pattern(conversionPattern: '%d{DATE} %X{requestId} %5p %c{1}:%L - %m%n')

我在#grails IRC频道得到了一个正确方向的推动

Log4J(或者实际上是SLF4J)有一个称为MDC(Mapped Diagnostic Context-)的东西,它本质上是一个线程本地映射。通过创建一个过滤器并向MDC添加所需的信息,我可以将此信息包含在该线程中执行的所有日志消息中

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

例如:

添加筛选器以生成和存储
请求ID

def filters = {
   all(controller:'*', action:'*') {
      before = {
         MDC.put 'requestId', UUID.randomUUID().toString()
      }
   }
}
在配置中,在模式中添加
%X{requestId}

log4j = {
  appenders {
      console name:'stdout', layout:pattern(conversionPattern: '%d{DATE} %X{requestId} %5p %c{1}:%L - %m%n')

我可能错了,但是在Grails项目中,
过滤器
不总是只接触
控制器
吗?你是对的。。。从技术上讲过滤器出现在控制器之前是的,但它实际上并不比任何其他层更接触它。诀窍在于过滤器获取请求并将处理该请求的线程的信息添加到SLF4J MDC中。如果您没有显式地对该请求进行多线程处理,那么无论您是在控制器、服务还是域中,您都应该始终能够访问相同的MDC。当然,如果您执行多线程处理或调用某些REST服务,您将遇到问题。啊-谢谢!我没有意识到这一点,但知道这一点真的很好:)我可能错了,但在Grails项目中,
过滤器
不是总是只接触
控制器吗?你是对的。。。从技术上讲过滤器出现在控制器之前是的,但它实际上并不比任何其他层更接触它。诀窍在于过滤器获取请求并将处理该请求的线程的信息添加到SLF4J MDC中。如果您没有显式地对该请求进行多线程处理,那么无论您是在控制器、服务还是域中,您都应该始终能够访问相同的MDC。当然,如果您执行多线程处理或调用某些REST服务,您将遇到问题。啊-谢谢!我不知道,但知道这一点真的很好:)