I soon wanted to do 3 things with logging in my Griffon app:
- Inject a logger (e.g. log4j) into all my MVC components.
- Filter out the cruft from Groovy's massive stacktraces.
- Log unhandled exceptions in the same way as everything else.
* Injecting log4j loggers in MVC components
I want to be able to write a log entry from anywhere in my MVC code, without needing to explicitly define the logger in each component. Griffon makes this easy ...
1. Grab a copy of log4j-1.x.xx.jar (there's one in GRIFFON_HOME/lib), and copy it into [projectname]/lib
2. Initialise logging at application startup:
Edit the file [projectname]/griffon-app/lifecycle/Initialize.groovy
To simply send logs to the console, just use BasicConfigurator. Add this line:
org.apache.log4j.BasicConfigurator.configure()
... Normally, you would use a PropertyConfigurator, or maybe even call System.setProperty to tell log4j about your log4j configuration file.
3. Inject a logger into each MVC component.
* Create or edit the file [projectname]/griffon-app/conf/Events.groovy
* Add the following (I added 'mvc.' to the logger name because my MVC components are all in the 'default' package):
import org.apache.log4j.Logger
onNewInstance = { klass, type, instance ->
instance.metaClass.logger = Logger.getLogger("mvc.${klass.name}")
}
Now, you can call logger.debug("variable x is ${x}") from anywhere in your Model, View and Controller classes.
Sweet.
* Filtering Groovy Stacktraces
Groovy generates extremely long, unwieldy stacktraces.
Just wrap this call around any Throwable, whenever you log it:
StackTraceUtils.deepSanitize(t)
e.g.
logger.error("Uncaught exception: ${e.message}", StackTraceUtils.deepSanitize(e))
... You could take this further and override 'logger.warn()' and 'logger.error()'
* Logging unhandled exceptions
I want to log unhandled exceptions in the same way I log everything else.
Simply configure an UncaughtExceptionHandler.
Again, I configure this in Initialize.groovy
1. Create an exception handler, something like this (I've put in the deepSanitize)
import org.apache.log4j.Logger
import org.codehaus.groovy.runtime.StackTraceUtils
import java.lang.Thread.UncaughtExceptionHandler
class LoggingExceptionHandler implements UncaughtExceptionHandler {
private static Logger logger = Logger.getLogger(LoggingExceptionHandler.class)
public void uncaughtException(Thread t, Throwable e)
{
logger.error("Uncaught exception ${e.message}", StackTraceUtils.deepSanitize(e) )
}
}
2. Configure the app to use the ExceptionHandler
Edit the file [projectname]/griffon-app/lifecycle/Initialize.groovy
Add the following lines, *after* the log4j configuration lines:
Thread.setDefaultUncaughtExceptionHandler(new LoggingExceptionHandler());
System.setProperty("sun.awt.exception.handler",LoggingExceptionHandler.class.getName())
Note that this replaces the functionality of griffon.util.GriffonExceptionHandler. If you prefer, you could extend this instead
HTH.
Amir