Wednesday, November 21, 2012

How to include session id and username in Grails logs

Introduction

It can be very useful in debugging problems to include the session id and the logged in user's username in your logs. Of course you can do it manually in every applicable log, but there is another way, a more Spring/Grails like way.

There is a feature in log4J called Mapped Diagnostic Context (MDC). This enables the storing of thread/request/context specific values in a map, that can be included in log output. To store something in this map you would write code like the following:

import org.apache.log4j.MDC
...
MDC.put("username", username)
This entry in the MDC map can then be referenced in an application's log4J conversion pattern. To add the username defined above you would have a pattern like:
%c{2} %X{username} %m%n

Grails Example

Let's now move to an example of how once could take advantage of MDC in Grails. Firstly, create a filter which will populate the MDC map. Such a filter could look like if you are using Spring Security:

class MyFilters {
  
  def springSecurityService

  def filters = {
    addAdditionalRequestInfoToLogs(controller: '*', action: '*') {
      before = {   
        MDC.clear()     
        MDC.put("sessionId", "[$session.id]")
        // try catch is good here because otherwise an error ends 
        // up creating stackoverflow scenario
        try { 
          def username = springSecurityService.principal?.username
          if (username) MDC.put("username", "[$username]")
        } catch (Exception e) { log.error "$e" }
      }
    }
  }

}

Now you only need to update your logging config and you wil be done. Open up your Config.groovy and track down your existing logging pattern definition. Here is one I have for development:

appenders {
      console name:'stdout', 
              layout: pattern(conversionPattern: '%c{2} %m%n')
    }

Now add references to the data we have put in the MDC:

appenders {
      console 
        name:'stdout', 
        layout: pattern(conversionPattern: '%c{2} %X{sessionId} %X{username} %m%n')
}

And that's it. You should be good to go for more informative logging!

Credits

3 comments:

  1. Thanks a lot for the article, this is exactly what I was searching for!

    ReplyDelete
  2. best food franchises Old New York Deli & Bakery. A place great tasting food & great people meet. A top food franchise to own and fast casual for breakfast, lunch & dinner. Hand made daily,

    ReplyDelete