1

Below is my logging configuration. It is logging exactly what I want, but it is only logging it to a file. I would like to see the same information on the console. I have tried several variations, but with every variation I can only get the information logged to either the console or a file, not both.

    def appName = grails.util.Metadata.current.'app.name'
    def catalinaBase = System.properties.getProperty('catalina.base')
    catalinaBase = catalinaBase ?: "."
    def logDirectory = "${catalinaBase}${File.separator}logs${File.separator}${appName}"

    // log4j configuration
    log4j = {
        appenders {
            rollingFile name: 'stdout',     file: "${logDirectory}${File.separator}${appName}.log".toString(), maxFileSize: '100MB' // Use the same file for stdout and stacktrace
            rollingFile name: 'stacktrace', file: "${logDirectory}${File.separator}${appName}.log".toString(), maxFileSize: '100MB' // Use the same file for stdout and stacktrace
        }

        warn   'org.codehaus.groovy.grails.web.servlet',        // controllers
               'org.codehaus.groovy.grails.web.pages',          // GSP
               'org.codehaus.groovy.grails.web.sitemesh',       // layouts
               'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
               'org.codehaus.groovy.grails.web.mapping',        // URL mapping
               'org.codehaus.groovy.grails.commons',            // core / classloading
               'org.codehaus.groovy.grails.plugins',            // plugins
               'org.codehaus.groovy.grails.orm.hibernate',      // hibernate integration
               'org.springframework',
               'org.hibernate',
               'net.sf.ehcache.hibernate'

        all    'grails.app.controllers.test',
               'grails.app.domain.test',
               'grails.app.services.test',
               'grails.app.taglib.test',
               'grails.app.conf.test',
               'grails.app.filters.test'
    }
ubiquibacon
  • 10,451
  • 28
  • 109
  • 179

2 Answers2

2

Firstly, having two different appenders that log to the same file is a bad idea, if you want the full stacktraces to go to the same place as the normal logs then you should re-point things at the logger level rather than the appender level.

For your actual problem, I would create a console appender and a single file appender, and attach them both to the root logger.

log4j = {
  appenders {
    console name:'stdout'
    rollingFile name: 'applog',     file: "${logDirectory}${File.separator}${appName}.log".toString(), maxFileSize: '100MB'
    'null' name:'stacktrace' // prevent Grails trying to create stacktrace.log
  }

  root {
    warn 'stdout', 'applog'
  }

  // Send full stack traces to the main appName.log file
  warn applog:'StackTrace'

  // individual warn/all logger configurations as before
}

This will send the same logs to stdout and to the log file, but will only send full stack traces to the file (not to the console). If you really do want the full stack traces on the console too then change it to

  warn applog:'StackTrace', stdout:'StackTrace'

Alternatively, you might consider disabling the StackTrace logger altogether (remove the whole warn applog:'StackTrace' line) and then also disabling stack trace filtering by setting the system property grails.full.stacktrace to true so you get full unfiltered stack traces recorded by the normal loggers.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Thanks! I think this gets it. I am curious though, why is it bad to have two appenders log to the same file? There isn't any chance of locking is there? I find it easier to debug a stacktrace when it is in the same context as info from the app log. – ubiquibacon Aug 26 '13 at 18:44
  • @ubiquibacon You _might_ get away with it (I'm not sure) for a plain FileAppender, but for a rolling file I'd be worried about what happens if both appenders try to roll the log file at the same time (or worse, at slightly different times - appender 1 renames app.log to app.log.1 and opens a new app.log, appender 2 then renames that new app.log to app.log.1 and you've lost the original log file). – Ian Roberts Aug 26 '13 at 18:59
  • I see now that by default it seems a partial stacktrace is included in `stdout`. That is actually all I wanted, so I don't have to merge the full stacktrace into the app log to get what I want. Thanks for getting me on the right track. – ubiquibacon Aug 27 '13 at 13:38
0

With your configuration above, for exmaple, to have all INFO-level 'grails.app' events log to console and your 'stdout' appender, you'd want something like the following:

log4j = {
   appenders { 
     ... appender configuration here ...
   }
   // configure a root logger
   root {
     warn 'stdout'
     additivity = false
   }

   info stdout:'grails.app'
   info console:'grails.app'

}
Aquatoad
  • 778
  • 8
  • 21
  • Do you care to provide an example? I have read the docs and I don't see how that will help. What I want is to use multiple loggers on a single appender. [Grails Logging Excerpt](http://grails.org/doc/latest/guide/conf.html#3.1.2%20Logging): ***Additivity simply determines whether a logger inherits the configuration from its parent.*** – ubiquibacon Aug 26 '13 at 16:05