Thanks for the reply, always great to get feedback.
The change is, unfortunately, definitely a major change. I had been planning on making it with liquibase 4 since I really don’t like making API-breaking changes, but it’s been a problem for far too long, and liquibase 4 is not moving as well as I would have liked. The logging cleanup dbmanul did also forced the issue as well.
Because it’s such an inherently breaking change, and is going to cause some redo of extensions regardless so I figured it would be best to focus on a good API going forward rather than keeping old names that may not work as well now.
However, your point about non-logger extensions breaking because they are using the existing liquibase logging system is a very good point. There will be some changes they will need to make, but if we can avoid some of the code changes that is always best.
So, I added back a liquibase.logger.LogFactory class with the same method signatures as before.
Because I changed to a forced classname based logging the LogFactory version that takes a string guesses it is a classname or otherwise has to use Liquibase.class. It’s not ideal, but I had purposely not included the string-named loggers to provide more consistency in how logs are named across plugins. My guess is most people used class names or the empty getLog() method anyway, but does anyone feel very strongly that non-class-name log names should be supported?
For source-level compatibility, I also added back the non-LogTarget versions of the methods in Logger and renamed “error” back to “severe” and “warn” back to “warning”.
The auto-closeable side of LoggerContext is nice because it lets you do:
and you don’t have to worry about not cleaning up the MDC at all.
However, the biggest reason for the LoggerContext was to provide hooks beyond to make the logging system useful for more than just writting strings to a text file. My idea is that LoggerContexts are a more complex object that allow parts of the program to more intelligently let the user know what is going on. Compared to standard MDC, the value can be an object rather than a string, and there are methods for showing progress on the current state.
Liquibase has a lot of ways that it can be ran, from a standard command line app, to a command line app that pipes to others, to embedded in a server to integrated into GUIs. I’m trying to find a good way to have the liquibase code (and extensions) be able to have simple log.info() style calls and the way those messages are returned can be handled flexibly.
In an server, the messages will just go to the log, but in a command line app you may want a more complex nested output like dbmanul’s TreeStyleLogger (which i took out for now) as an option, and in a GUI you may want to show progress dialogs for long-running operations.
LoggerContext is trying to be a generic MDC yet add a few more features to allow better user interaction within each context.
LogTarget is another feature in my attempt to have a better unified way to have code simply log what it’s doing and have different Liquibase interfaces handle those messages in the best ways for them.
SQL logging vs. regular logging is a good example of where we’ve seen the problem. There have been several attempts (including dbmanul) to introduce a SQL log level so that people can see what SQL has been ran (sometimes DML, sometimes queries, sometimes both), but a SQL log level doesn’t work well because where does it fit into the level hierarchy? It’s not really more severe than “severe”, but that is what you need to do to get only SQL. And if you do that, you always get SQL if you just want error messages.
LogTarget is basically the same as Markers, just a bit more constrained in what the available options are. It lets the code making a log message at any level be able to say what kind of message it is and leave it up to the logger as configured by the integration to handle it as it sees fit.
One big help for the LogTarget is in the Liquibase 4 code: I simplified the database interaction so there is no longer the separate code paths for updateSql vs update mode and have a new “update and also output the SQL” mode. There is a common location that ALL sql calls to the database now go through that can simply log.info(LogTarget.SQL, sqlStatement) the statement as it goes to the database and the CLI can send the sql to the correct location independently from any logging it does.