Reload tomcat logging at runtime?

2020-04-20 08:37发布

问题:

We are currently using Tomcat 7 with a single log configuration specified using -Djava.util.logging.config.file and the default ClassLoaderLogManager with -Djava.util.logging.manager="org.apache.juli.ClassLoaderLogManager". This works great for a one-time startup config.

We have several servlets and other code that runs outside the servlet context. We run on a dedicated tomcat server that we completely control, and we want all the code to use the same log configuration. We are using the java.util.logging API for logging. This means that LogManager.getLogManager().getLogger(name) needs to work, and that Logger.isLoggable(Level) needs to work.

ClassLoaderLogManager seems geared towards the opposite of our situation: allowing servlets to specify individual log settings. We want all the logs controlled in one place. But, we do want the other JULI benefits like the improved FileHandlers.

Now the question: How can I reload these settings from the file at runtime without reloading the application?

What I've tried:

  • LogManager.getLogManger.readConfiguration(): results in an effective NOOP in ClassLoaderLogManager because Thread.currentThread.getContextClassLoader() isn't the system classloader.
  • Explicitly setting Thread.setContextClassLoader(ClassLoader.getSystemClassLoader()) and then calling the above. This did actually read the config file (stepped through in a debugger) but it didn't propagate the changes down to existing loggers in the contained ClassLoaders. Logger.setLevel() was never called on existing loggers.
  • also calling reset() before these calls doesn't seem to change anything.
  • JMX appears to only expose the loggers for a single ClassLoader (possibly the system ClassLoader)

回答1:

I found one solution to this. Replacing the log manager in the startup script with the default java.util.logging.LogManager or simply deleting the command line argument results in the regular LogManager being used. This LogManager will fully reload the configuration for all Loggers in all ClassLoaders when readConfiguration() is called, exactly the behavior I need.

This does involve modifying the tomcat startup scripts, however. If someone can find a better solution without doing that, that would be great, otherwise I'll accept this answer.



回答2:

If your not married to Tomcat JULI you might want to consider using Logback since IMHO its the only the that reliably handles log configuration reloading during runtime.

I haven't done this myself but some one has written a guide: Logging with SLF4J and Logback in Tomcat and TomEE which basically using a bunch of bridge jars.

The other thing you might consider is just using per web app logging with Logback and just ignore Tomcat's JULI logs (thats what I do).

CAVEAT: http://www.slf4j.org/legacy.html#jul-to-slf4j ... consequently please never use JUL directly.... Guava and Tomcat are on my $hit list for using JUL.