Sublog: Enhanced Logging

Summary

Installation

grails install-plugin sublog

Description

Provides a convenient way to access sub-loggers and automatically cleans up rough edges in Grails logging.

While working on articles for the July/August GroovyMag, I decided to do some cool things with Grails logging. The result is Sublog (Sublime Logging): a plugin with a few Grails logging improvements. Despite the 0.x version number, this plugin is tested and stable: the integration tests for the functionality so far is very straightforward. It's just 0.x due to a lack of particularly fancy functionality, and my suspicion that I'll add more functionality as I think of it.

Improvements

First, the level-based log methods ("trace", "debug", ..., "fatal") that take a Throwable now run that throwable through GrailsUtil.deepSanitize before logging them. This should substantially reduce the noise in a lot of logging messages. (Technical note: Yes, I am aware of the potential for a stack overflow exception because of the Stacktrace logger. Yes, I have dealt with that so you don't have to worry about it.) The original (non-sanitizing) versions are available under "xxxRaw" (traceRaw, debugRaw, ..., fatalRaw). Note that since this is implemented via metaClass mangling, the filtering is only available when you call a logger in Groovy code: calls from Java will not be automatically reduced.

Second, any logging instance can now give you a child through property navigation. So if you have a domain class Foo (with its Logger, "log"), and you want to create a new category of logging messages for suspicious behavior, you can simply say log.suspicious.warn("Not sure I like this: ..."). Thanks to the miracle of logging additivity, log.suspicious will have the same log levels, etc., as the parent logger, but you will later have the ability to turn off that particular category of logging without disabling logging all around. This gives much more fine-grained control over logging.

Third, artifacts now have a static "log" property (in addition to an instance "log" property), and the implementation of the logger is Log4J (instead of the API-poor SLF4J). Note that actually calling the static property can be a bit tricky, since Groovy's a bit over-excited about checking field values: just use 'getLog()' instead of 'log', and you should be okay.

Fourth, you can explicitly attach a static "log" property which is the Log4J logger you'd expect it to be by using the following annotation on your class:

@WithLog
class Foo {
/* [YOUR IMPL HERE] */
}

Fifth, loggers now take a closure in order to prevent evaluating the GString.