Redirecting "derby.log" To An SLF4J Logger

2012-07-28 22:35UTC

More and more, I find myself using Apache Derby as an embedded database for personal projects. One inconvenience, however, is the persistent derby.log file than inevitably gets created at startup. It can, of course, be disabled entirely, but I'd like Derby errors to be put into my application logs, currently managed by an SLF4J provider.

I devised a quick solution that seems to enable this behaviour. While I have not thought of any issues with this approach, I would advise against using this code in a production system without sufficient testing. The solution, itself, is very simple and lies in Derby's hook to manually specify a log writer:

derby.stream.error.method=ca.burnison.infrastructure.persistence.derby.DerbySlf4jBridge.bridge

Simply, a basic java.io.Writer implementation that overrides write(char[], int, int) to invoke a logger will provide a basic solution. Threshold selection is possible, however, is beyond the scope of this excerpt.

/**
 * Funnels Derby log outputs into an SLF4J logger. This current implementation logs
 * all errors at the <code>ERROR</code> threshold.
 */
public final class DerbySlf4jBridge
{
    private static final Logger logger = LoggerFactory.getLogger(DerbySlf4jBridge.class);

    private DerbySlf4jBridge()
    {
    }

    /**
     * A basic adapter that funnels Derby's logs through an SLF4J logger.
     */
    public static final class LoggingWriter extends Writer
    {
        @Override
        public void write(final char[] cbuf, final int off, final int len)
        {
            // Don't bother with empty lines.
            if (len > 1)
            {
                logger.error(new String(cbuf, off, len));
            }
        }

        @Override
        public void flush()
        {
            // noop.
        }

        @Override
        public void close()
        {
            // noop.
        }
    }

    public static Writer bridge()
    {
        return new LoggingWriter();
    }
}

Once the system property is set (either by derby.properties or -Dderby.stream.error.method=...), Derby's logs will be sent to your SLF4J logger, allowing you to apply filtering and logger redirection as you wish.