How to get liquibase to log using slf4j?

22,903

Solution 1

There is, but it is a little bit obscure. Quoting Fixing liquibase logging with SLF4J and Log4J:

There's The Easy Way, by dropping in a dependency:

<!-- your own standard logging dependencies -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.5</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId><!-- or log4j2 or logback or whatever-->
    <version>1.7.5</version>
</dependency>

<!-- special dependency to fix liquibase's logging fetish -->
<dependency>
    <groupId>com.mattbertolini</groupId>
    <artifactId>liquibase-slf4j</artifactId>
    <version>1.2.1</version>
</dependency>

Now the first two are your everyday logging frameworks (slf4j api and log4j implementation). These are in addition to your standard log4j dependency, as all they do is route to the physical logging framework. Without log4j/logback/etc. itself, they still can't route anything.

The last one however, is an interesting one, as it provides a single class in a specific package that liquibase will scan for Logger implementations. It's open source, by Matt Bertolini, so you can find it on GitHub.

If you wish to do this yourself, there's also The Hard Way:

package liquibase.ext.logging; // this is *very* important

import liquibase.changelog.ChangeSet;
import liquibase.changelog.DatabaseChangeLog;
import liquibase.logging.core.AbstractLogger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Liquibase finds this class by itself by doing a custom component scan (sl4fj wasn't generic enough).
 */
public class LiquibaseLogger extends AbstractLogger {
    private static final Logger LOGGER = LoggerFactory.getLogger(LiquibaseLogger.class);
    private String name = "";

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void severe(String message) {
        LOGGER.error("{} {}", name, message);
    }

    @Override
    public void severe(String message, Throwable e) {
        LOGGER.error("{} {}", name, message, e);
    }

    @Override
    public void warning(String message) {
        LOGGER.warn("{} {}", name, message);
    }

    @Override
    public void warning(String message, Throwable e) {
        LOGGER.warn("{} {}", name, message, e);
    }

    @Override
    public void info(String message) {
        LOGGER.info("{} {}", name, message);
    }

    @Override
    public void info(String message, Throwable e) {
        LOGGER.info("{} {}", name, message, e);
    }

    @Override
    public void debug(String message) {
        LOGGER.debug("{} {}", name, message);
    }

    @Override
    public void debug(String message, Throwable e) {
        LOGGER.debug("{} {}", message, e);
    }

    @Override
    public void setLogLevel(String logLevel, String logFile) {
    }

    @Override
    public void setChangeLog(DatabaseChangeLog databaseChangeLog) {
    }

    @Override
    public void setChangeSet(ChangeSet changeSet) {
    }

    @Override
    public int getPriority() {
        return Integer.MAX_VALUE;
    }
}

This implementation works, but should only be used as an example. For example, I'm not using Liquibase's names to require a logging, but use this Logger class itself instead. Matt's versions does some null-checks as well, so that's probably a more mature implementation to use, plus it's open source.

Solution 2

I am not very sure about your requirement but what I understand is that You want to logged all liquibase log using SLF4J API. If I am right then I guess you can able to do it.

First add following dependency into your pom.xml file :

<dependency>
    <groupId>com.mattbertolini</groupId>
    <artifactId>liquibase-slf4j</artifactId>
    <version>1.2.1</version>
</dependency>

<dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.6</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>
        <version>1.6.6</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.0.7</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.0.7</version>
    </dependency>

and into your logback.xml file, Add logger for liquibase and set LEVEL as per your requirement.

  <logger name="liquibase" level="DEBUG" />

Solution 3

Here is my recipe to make liquibase 3.5.3 log into file under windows when running from command line. It doesn't use exactly 'slf4j' but solves the problem of getting log files of db updates, by making liquibase use java.util.logging.

1) get the liquibase-javalogger-3.0.jar from here https://github.com/liquibase/liquibase-javalogger/releases/

2) put it to %LIQUIBASE_HOME%/lib directory

3) create logger.properties file with the following content:

handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level=FINEST
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.pattern=liquibase.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.append=true
#2018-04-28 17:29:44 INFO Example logging record
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %5$s%6$s%n

4) add java option to liquibase (for example via set JAVA_OPTS=...):

-Djava.util.logging.config.file=logger.properties

Example of my liquibase wrapper batch file :

set username=%USER%
set password="%PASSWORD%"

set URL="jdbc:db2://mydbserver:50000/MYDB"

set JAVA_OPTS=-Djava.util.logging.config.file=db2/logger.properties

call liquibase.bat ^
    --driver="com.ibm.db2.jcc.DB2Driver" ^
    --defaultSchemaName=MYSCHEMA ^
    --liquibaseSchemaName=MYSCHEMA ^
    --changeLogFile=db2/changelog.xml ^
    --url=%URL% ^
    --username=%USER% ^
    --password="%PASSWORD%" ^
    --logLevel=debug

UPDATE:

I've switched to new liquibase version which is using logback by default. For liquibase 3.6.2 use the following setup to run from windows command line:

1) Ensure slfj is reachable in java classpath. Put the slf4j-api-1.7.25.jar in liquibase/lib folder. The jar file can be found in the official slfj distribution package: https://www.slf4j.org/download.html

2) Set logback configuration file path parameter:

JAVA_OPTS=-Dlogback.configurationFile=logback.xml

3) Add logback.xml configuration file. Example is here: https://www.mkyong.com/logging/logback-xml-example/

Share:
22,903
Benny Bottema
Author by

Benny Bottema

Updated on January 18, 2020

Comments

  • Benny Bottema
    Benny Bottema over 4 years

    A lot of people are unsure how to fix logging for liquibase, either to the console or file.

    Is it possible to make liquibase log to slf4j?