Uploaded image for project: 'Log4j 2'
  1. Log4j 2
  2. LOG4J2-2240

Is there a mechanism to reconfigure log4j2 in a predictable fashion?

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Open
    • Critical
    • Resolution: Unresolved
    • 2.10.0
    • None
    • Core
    • None

    Description

      Hello, I'm re-posting from Stack Overflow following Remko Popma's recommendation. This is simultaneously a question and a request for improvement. If there is a trick I haven't discovered yet it can be used as a workaround, however, the absence of a public API to the Configurator that would support reconfiguration and allow (even if optionally) handling of abnormal events appears to be a serious deficiency that could hopefully be addressed in the near future. Thanks!

       ------------------------------------------------------------------------------------------------------------------------

      I'm looking for ways to configure/reconfigure log4j after it may, or may not have been initialized. This should work running standalone or in a web container.

      The configuration may be represented by a configuration file at a particular arbitrary URI. The knowledge of the URI comes from the application, not log4j framework. The configuration may also be done programmatically (less problematic but problematic still).

      The public API is unfortunately sorely lacking so developers are forced to write brittle code using implementation classes from log4j core. From weeks of studying documentation and stepping through log4j code I see two ways to accomplish reconfiguration:

      Stopping the current context and re-initializing using log4j.core.config.Configurator,
      similar to the following:

      ((LoggerContext) LogManager.getContext(false)).stop();
       Configurator.initialize(buildDefaultConfiguration()); //programmatically building a configuration

      or

      ((LoggerContext) LogManager.getContext(false)).stop();
       Configurator.initialize(null, ConfigurationSource.fromUri(loggingUri)); //passing the configuration source constructed from a known URI

      The first line in both examples will stop the current context if it has already been created and started (when running in a web container for example). If log4j has not been initialized (when running as a standalone app for example) it will initialize log4j with the default configuration and start the context first (as a side effect of calling getContext()), and then stop it.

      If the current context is not stopped first the call to Configurator.initialize() will have no effect. log4j will ignore your attempt to re-initialize, will not give you any indication of it, and just simply return the current context. This behavior is not mentioned in the "Reconfigure Log4j Using ConfigurationBuilder with the Configurator" section of the Manual. It simply says: "However, should any logging be attempted before Configurator.initialize() is called then the default configuration will be used for those log events." The default configuration will also be used for all subsequent log events in the provided examples because calling Configurator.initialize() will have no effect, unless the current context is stopped first.

      Setting a new configuration location on the existing context thus forcing reconfiguration,
      similar to the following:

      ((LoggerContext) LogManager.getContext(false)).setConfigLocation(loggingUri);

      This works in a similar fashion: if log4j hasn't been initialized the call to getContext() will trigger initialization and creation of the default context that will then be reconfigured; and if it has been initialized then the current context, whatever it may have been, will get reconfigured. The configuration source will be created from the URI by the log4j framework.

      The difference is that in the first way the context is replaced and all loggers in the old (stopped) context will be dead. If any code on the stack holds references to these dead loggers and tries to log to them it will be a no-op. In the second way the context is kept but the configuration is replaced and existing loggers are updated with the new configuration.

      Both methods use core code and are therefore brittle, but both work for the sunny day scenario (using log4j-core 2.10.0 anyway). However, neither one appears to afford the user any control over handling any exceptional events, or even inform the user that something went wrong. Log4j will "eat up" any exceptions, and make its own executive decision how to handle them.

      If a problem occurs after Configurator.initialize() is called log4j will create a default configuration that effectively cuts all logging off other than errors to the console and happily return the new context back not giving the calling code any clue that logging has effectively been stopped.

      If a problem occurs after LoggerContext.setConfigLocation() is called log4j will do essentially the same thing except the current context will be kept. One would think that particularly in the case of a reconfiguration failure the most typical handling would be to revert back to the old configuration. There doesn't appear to be a way to accomplish this because log4j will simply stop logging (other than errors to the console) and give the calling code no indication of the failure.

      Here's a typical scenario: several applications extend a common framework. The framework configures the same logging for all extending applications (to facilitate reuse and simplify post-processing of the logs). Some application has a unique logging need and attempts to reconfigure log4j from its own metadata (config file at a known URI). The XML parser throws an exception parsing this file. The exception gets handled internally by log4j, logging is quietly stopped, and no one knows. Well, there is an error log sent to the StatusLogger with the exception, but the calling code doesn't know.

      So with this lengthy preamble, the question is: is there a mechanism I haven't discovered yet to modify log4j configuration in a predictable fashion and be able to handle abnormal events should they arise? That is, other than something drastic like (for the example above) extending the XML configuration class and replacing code that handles exceptions, thus running a risk of creating undesirable side effects in the current log4j implementation, not talking about an even greater risk of breaking in the future if the implementation changes.

      Any help would be greatly appreciated!

      Attachments

        Activity

          People

            rgoers Ralph Goers
            Pershwitz Edward Pershwitz
            Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated: