4

I have configured log4j appenders in my application to send mails in case of any exception.

Code looks like this in Config.groovy :

log4j = {
    appenders {
    String currentUrl = grails.serverURL
    String currentEnv = 'Production'
    if (Environment.isDevelopmentMode()) {
        currentEnv = 'Development'
    } else if (currentUrl.indexOf('test') > -1) {
        currentEnv = 'Testing'
    }
    console name: 'stdout', layout: pattern(conversionPattern: '[%r] %c{2} %m%n')
    // if real password is needed, please contact IT department
    def patternLayout = new PatternLayout()
    patternLayout.setConversionPattern("[%r] %c{2} %m%n")
    def mailAppender = new SMTPAppender()
    mailAppender.setSMTPUsername('a@abc.com')
    mailAppender.setSMTPPassword('password')
    mailAppender.setFrom("x@xyz.com")
    mailAppender.setTo("user@domain.com")
    mailAppender.setSubject("A log4j error has been generated in the [${currentEnv}] environment.")
    mailAppender.setSMTPHost("smtp.elasticemail.com")
    mailAppender.setSMTPPort(2525)
    mailAppender.setBufferSize(4096)
    mailAppender.setLayout(patternLayout)
    appender name: 'mail', mailAppender

    root {
        error 'stdout', 'mail'
        additivity = true
     }
   }
 }

I want to include in subject, the current login user from whose screen error originates. I am using spring security plugin and grails version is 1.3.7

I have the following code:

def user
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
   user = org.abc.com.Person.get(appCtx.springSecurityService.currentUser.id)
}

outside log4j and used user instance in subject but it returns null.

Is their any other way to get current user in subject.

Any way to do so? Please suggest

Also is their any way to send mail asynchronously?

Opal
  • 81,889
  • 28
  • 189
  • 210
Charu Jain
  • 852
  • 1
  • 7
  • 18
  • 1
    The config read once at start. The `user` is changing in the runtime. So, if you want to send the user name by e-mail, then you should to do it in runtime (some Controller, or Service, etc.) – wwarlock Aug 27 '14 at 06:44
  • This log4j appenders are written in config.groovy file only. so there is no way to go inside controller or service. – Charu Jain Aug 27 '14 at 08:00
  • Yes, I know it and wrote about it. Go to your Controller and write something like `log.debug "session id: ${sessionId}, user: ${currentUser}"`. And this log will be e-mailed as you configured in `Config.groovy` – wwarlock Aug 27 '14 at 08:04
  • okay, that could be done. But since this appender works for both handled(marked by try/catch) and unhandled exceptions. For handled exceptions i need to write log.error to allow mailing. & your solution would work perfect in that case. But what for the case of unhandled exception? Your solution would require me to handle exception everywhere in code and say a log.error "username" everywhere, that i don't want – Charu Jain Aug 27 '14 at 08:11

2 Answers2

2

Based on the pointer from Joshua , I found an awesome blog entry by Burt on the same problem.

http://burtbeckwith.com/blog/?p=521

It is the exact answer for the problem , I was looking for.

Charu Jain
  • 852
  • 1
  • 7
  • 18
1

The key here is going to be using log4j Nested Diagnostic Contexts. The documentation for log4j outlines your use case.

To illustrate this point, let us take the example of a servlet delivering content to numerous clients. The servlet can build the NDC at the very beginning of the request before executing other code. The contextual information can be the client's host name and other information inherent to the request...

Translating that into Grails isn't too difficult. Create a filter which will apply to all requests, populates the NDC with the appropriate information before the call to any controller and action and then clears it after the call.

Once you have this information exposed in the NDC then you can of course add it to your logging pattern.

That's the correct way to address this issue.

Joshua Moore
  • 24,706
  • 6
  • 50
  • 73