Grails 1.0.x started creating a stacktrace.log file in the directory where the servlet container starts. In a development environment, using grails run-app, that’s simple enough— it appears in the top level of your application. In a production environment, this becomes a problem. Your production container (e.g. Tomcat) may start someplace where it can’t create files, like /. Thus you get exceptions sent to your container’s log files like:
java.io.FileNotFoundException: stacktrace.log (Permission denied)
Also, messages are appended to stacktrace.log– so it will continue to grow if you don’t do something about it. One option is to change where your container starts, e.g. have the startup script change to its logs directory. You can also configure your grails app to change the location of the stacktrace.log file or turn it off completely.
Changing file location
To change the file location/name, edit your grails-app/conf/Config.groovy file. In Grails 1.0.3, you want to change the line:
appender.'stacktraceLog.File'="stacktrace.log"
to something like:
appender.'stacktraceLog.File'="/var/log/myapp/stacktrace.log"
In Grails 1.0, 1.0.1, and 1.0.2, the property is:
appender.'errors.File'="stacktrace.log"
Turning off stacktrace.log
To turn off the log file completely, in 1.0.3 change the line:
StackTrace="error,stacktraceLog"
to:
StackTrace="error"
In previous versions, the original line is:
StackTrace="error,errors"
What we are doing is removing the only appender from the StackTrace logger (automatically created by Grails) so the messages will not be written anywhere (and the file will not be created). The word error that remains indicates the logging level. We could also change it to off to be clear (only doing that without removing the appender will still result in an attempt to create the file).
No stacktrace processing
According to the Grails docs, you can also turn this off by setting a command line property:
grails -Dgrails.full.stacktrace=true run-app
(yes, true) If you don’t also turn off the logging property, the stacktrace.log file will still be created but won’t be written to. Putting that line in Config.groovy doesn’t do anything. It also doesn’t help when creating a war for deployment. You’ll have to put that property definition into your container startup (setting the environment variable CATALINA_OPTS or adding to your jsvc command line).
Console logging
The docs also suggest sending the stacktrace to the console (for Tomcat 5.x that’s $CATALINA_HOME/logs/catalina.out), by changing the stacktraceLog or errors appender in the above line to stdout, like this:
StackTrace="error,stdout"
But error messages seem to go to the console anyways and so will be doubled.
Environments
You can make these changes for different environments. In Config.groovy add something like this:
environments { production { log4j.logger.StackTrace="error" } }
which will turn off the stacktrace logging file for your production environment, but leave it on for development.
Upgrades
I didn’t notice all this until just now with my new grails projects, because my original Grails projects were created before these shenanigans started happening. I’ve done grails upgrade several times since then, but stacktrace.log configuration isn’t yet in the upgrade script.
Grails 1.1 update
Grails 1.1 introduces a new Log4J DSL that completely changes this. I could not immediately get the above methods working. There are several undocumented behaviors that both cause and cure this. Assigning a different appender to the StrackTrace logger sends the stacktraces to that appender but it does not prevent the creation of a FileAppender named stacktraceLog and thus the file stacktrace.log is still created.
Reviewing the code (Log4jConfig.groovy), I found that the stacktraceLog appender is not created if an appender named stacktrace already exists, i.e. it’s created at the top of the log4j DSL closure. You can create a different file or rollingFile appender or whatever you like, just use name:'stacktrace'.
I like to turn off stacktrace logging completely. It’s an error, so it’s already going to the root logger anyways. Or I may want to send it to my appender named something else (like ‘tomcatLog’, which I use for other loggers and don’t want to call it ’stacktrace’). Use the undocumented NullAppender which exists in Grails by default. Create an appender of type 'null' — with quotes to avoid referencing the null object:
log4j = {
appenders {
'null' name:'stacktrace'
...
}
...
}
Hi, Thanks for your tip (Grails 1.1 update) it worked for me!