Fixing liquibase logging (in Spring) with SLF4J and Log4J

PDF

It took me awhile to figure it out, but I figured out how to run the liquibase logging through slf4j/log4j/logback etc, for Liquibase 3.0.8. There’s an easy way and a hard way. The easy way is just the hard way pre-packaged as a jar for you. You’ll understand.

The easy way

Drop in a jar called liquibase-slf4j, by Matt Bertolini, and configure its class logging through slf4j instead. In my case I’m using slf4j-log4j12 on top of that so I configure everything log4j style (make sure you have log4j on your classpath!).

Then to actually configure its output in log4j:

There’s also logging for “liquibase.integration.spring.SpringLiquibase” but that is only warn() and error(), so you should see that always anyway

The hard way

The difficulty in configuring Liquibase logging lies in that Liquibase invented its own ‘independent’ logging framework. The rationale is that in doing so it doesn’t have ‘an extra dependency‘, even though slf4j is meant to cut implementation dependencies so you’re free to use whatever you want. The fact that Liquibase’s logging approach changed drastically over several versions didn’t help; the core Liquibase developer, Nathan Voxland, constantly reminds people he still needs to fix the logging plugins and tells people to do some hokey pokey magic code to make it work (and not every time the same hokey pokey magic code, mind you).

Then there’s this little gem of SpringLiquibase javadoc in case you’re using Liquibase as a Spring bean. It mentions how you can configure an sqlOutputDir, but that property doesn’t exist anymore. Obsolete javadoc and no way to know how to do it now but to delve into the code. Oh and btw, Liquibase is doing its own magic generic class lookup with custom classloading and whatnot, so no, the code did not tell me properly what to do. But, we’re getting very close to the solution now…

Finally, I found that this specific instruction to makes the magic happen with the current latest version 3.0.8:

Basically you need to create a new class that extends liquibase.logging.core.AbstractLogger and overrides the getPriority method to return larger than 1 and the debug(), info() etc. methods. If you make the class in a sub-package of liquibase.ext it will automaticaly be picked up by liquibase and used.

So. A class extending AbstractLogger that has to be in a package called “liquibase.ext.logging”. Nice! I love it! Nothing says self-explanatory package structure like a random plugin extension folder for liquibase with one class to circumvent its own logging fetish. Awesome also that if they do change any of this, this approach will silently fail and fall back on Liquibase’s own default logger.

And this is exactly what Matt Bertolini did in liquibase-slf4j.

Tags:
  • Teresa Carrigan

    Thanks very much! The easy way worked perfectly for me in my Java project using Gradle and logback (after translating the lines from Maven and log4j).

    Reply

  • Christian

    Thanks a lot. Saved my day!

    Cheers,
    Christian

    Reply

  • nathan voxland

    Thanks for working through how to get it working. You will be glad to know slj4j will be in liquibase 4.0, finally

    Reply

Leave a Reply