Load Log4j2 configuration file programmatically
Asked Answered
D

9

50

I want to load Log4j2 XML configuration file programmatically from my application.

Tried this:

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
Configurator.initialize(null, source);

and this:

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
ConfigurationFactory factory = (ConfigurationFactory) XMLConfigurationFactory.getInstance().getConfiguration(source);
ConfigurationFactory.setConfigurationFactory(factory);

But nothing works yet.

Deal answered 13/1, 2014 at 4:21 Comment(1)
with all the backward incompatible changes introduced to the configuration reloading in log4j2 it would make sense to specify which version of the log4j2 api and core you are using ...Leucite
D
18

Found the answer myself. Someone might find it useful.

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
source.setFile(new File(logConfigurationFile));
source.setInputStream(new FileInputStream(logConfigurationFile));
Configurator.initialize(null, source);
Deal answered 13/1, 2014 at 9:37 Comment(10)
I'm trying to do the same thing but am failing even with the code above. Did you have the log4j2 web dependency in your project? My log4j2.xml is outside the classpath and I'm trying to load it up in a Spring bean that has a @PostConstruct method.Athalia
My log xml configuration file was outside the classpath.Deal
Was your application a web app? I should mention I am using slf4j as well to abstract log4j2.Athalia
Yes it was a web app. And I also used slf4j for routing jcl logs to log4j2.Deal
Is the @PostConstruct method being called when the server starts? Can you use a simple listener? Register it in web.xml and write this code in the overridden method contextInitialized of a class that implements ServletContextListener.Deal
Yes the @PostConstruct method is being called on server startup. I put the code you mentioned in your answer in the method. No exception was thrown and no log files were created in the directory I specified in my configuration. Here is my log4j2 config: pastebin.com/wSWWk2kb Maybe something is wrong with my configuration.Athalia
Let us continue this discussion in chat.Deal
I was able to get this working with the config outside the web app by using the log4jConfiguration context param in the web.xml as in this link: logging.apache.org/log4j/2.x/manual/webapp.html#Servlet-3.0Athalia
okay cool. this answer is based on Servlet 2.5 ... anyhow great that its working!Deal
why pass null to the Configurator.initialize() ?Drank
C
45

For the newest version of log4j, here is what should work for loading an external log4j2.xml:

String log4jConfigFile = System.getProperty("user.dir") + File.separator + "log4j2.xml";
ConfigurationSource source = new ConfigurationSource(new FileInputStream(log4jConfigFile));
Configurator.initialize(null, source);
Colubrid answered 24/2, 2015 at 16:32 Comment(2)
You should be able to use simply Configurator.initialize(null, "fileName");Ketchan
why pass null to the Configurator.initialize() ?Drank
Z
25

If you have a single main entry point, this code snippet might save you some trouble. The set property call must fire before any loggers are created. This approach works with files on the classpath.

public class TestProcess {
    static {
        System.setProperty("log4j.configurationFile", "log4j-alternate.xml");
    }

    private static final Logger log = LoggerFactory.getLogger(TestProcess.class);

}
Zachar answered 17/9, 2014 at 3:1 Comment(3)
This worked excellent, I was trying to set the property on Constructor, but it didn't work. Static block solved.Acrolith
I had setProperty() call but not in "static" block. It worked once I kept the call in the static block. Thanks!Belike
Won't changing the system property affect other logger's?Burtonburty
D
18

Found the answer myself. Someone might find it useful.

ConfigurationSource source = new ConfigurationSource();
source.setLocation(logConfigurationFile);
source.setFile(new File(logConfigurationFile));
source.setInputStream(new FileInputStream(logConfigurationFile));
Configurator.initialize(null, source);
Deal answered 13/1, 2014 at 9:37 Comment(10)
I'm trying to do the same thing but am failing even with the code above. Did you have the log4j2 web dependency in your project? My log4j2.xml is outside the classpath and I'm trying to load it up in a Spring bean that has a @PostConstruct method.Athalia
My log xml configuration file was outside the classpath.Deal
Was your application a web app? I should mention I am using slf4j as well to abstract log4j2.Athalia
Yes it was a web app. And I also used slf4j for routing jcl logs to log4j2.Deal
Is the @PostConstruct method being called when the server starts? Can you use a simple listener? Register it in web.xml and write this code in the overridden method contextInitialized of a class that implements ServletContextListener.Deal
Yes the @PostConstruct method is being called on server startup. I put the code you mentioned in your answer in the method. No exception was thrown and no log files were created in the directory I specified in my configuration. Here is my log4j2 config: pastebin.com/wSWWk2kb Maybe something is wrong with my configuration.Athalia
Let us continue this discussion in chat.Deal
I was able to get this working with the config outside the web app by using the log4jConfiguration context param in the web.xml as in this link: logging.apache.org/log4j/2.x/manual/webapp.html#Servlet-3.0Athalia
okay cool. this answer is based on Servlet 2.5 ... anyhow great that its working!Deal
why pass null to the Configurator.initialize() ?Drank
J
11

Below worked for me, Log4j2 with SLF4J wrapper:

Solution 1:

public class MyClass {

    static {
        try {
            InputStream inputStream = new FileInputStream("C:/path/to/log4j2.xml");
            ConfigurationSource source = new ConfigurationSource(inputStream);
            Configurator.initialize(null, source);
        } catch (Exception ex) {
            // Handle here
        }
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class); // LogManager if not using SLF4J

    public void doSomething() {
        LOGGER.info(...)
    }

}

Solution 2:

static {
    File log4j2File = new File("C:/path/to/log4j2.xml");
    System.setProperty("log4j2.configurationFile", log4j2File.toURI().toString());
}

Need toURI() to follow File URI Scheme format, else it throws MalformedURLException.

Sources:

Jessamine answered 7/7, 2018 at 11:19 Comment(2)
What if mine is a .properties fileLebkuchen
@silver why pass null to the Configurator.initialize() ?Drank
S
4

If you are using a Servlet 3.0 Web Application you can use the Log4jServletContextListener and do the following:

Write a custom LogContextListener which extends from Log4jServletContextListener, set it up in your web.xml and disable auto initialization:

<listener>
    <listener-class>com.example.LogContextListener</listener-class>
</listener>
<context-param>
    <param-name>isLog4jAutoInitializationDisabled</param-name>
    <param-value>true</param-value>
</context-param>

In your custom LogContextListener overwrite contextInitialized and set the config location

public void contextInitialized(ServletContextEvent event) { 
    /* Some logic to calculate where the config file is saved. For 
     * example you can read an environment variable.
     */
    String pathToConfigFile = ... + "/log4j2.xml";
    Configurator.initialize(null, pathToConfigFile);
    super.contextInitialized(event);
}

The advantage over configuring the location directly in the web.xml is that you can compute the path based on some additional information and access the log4j2.xml even if its outside of your classpath.

Spermophyte answered 1/5, 2015 at 21:9 Comment(1)
I used similar solution with log4j 1.2.x but unable to get working 2.14.x. The reason is, that my "LogContextListener" is created after log4j2 is already initialized with WARN StatusLogger No Log4j 2 configuration file found. Using default configuration... I guess it used to be the same for log4j v1 but with PropertyConfigurator.configure(logConfigProperties); it has reconfigured current log4j but this doesn't happen with Configurator.initialize(null, logConfigSource); My listener is the first one in web.xml but there are others in TLD files that are fired before.Pierian
K
3

Considering - https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/config/Configurator.html

Configurator.initialize(null, "classpath:conf/logger.xml");
or
Configurator.initialize(null, "/full_path/conf/logger.xml");

Be aware and does not use both at the same time.

Kitchenette answered 17/3, 2018 at 9:43 Comment(3)
why pass null to the Configurator.initialize() ?Drank
Please check upper javadoc link.Kitchenette
the 1st arg is the classloader but the javadoc doesn't tell much more; if I understood the code correctly if null it will use the classloader used to load log4j2 (more precisely Configurator.class.getClassloader())Maloney
G
3

If you config with .properties file:

String propertiesFile = "./test/Configuration/log4j2.properties";  
ConfigurationSource source = new ConfigurationSource(new FileInputStream(propertiesFile), new File(propertiesFile));
Configurator.initialize(null, source);
Grayce answered 12/11, 2019 at 8:52 Comment(0)
R
1
final URL log4j = Resources.getResource("log4j2-test.xml");
LoggerContext.getContext(false)
  .start(new XmlConfiguration(new ConfigurationSource(
    Resources.asByteSource(log4j).openStream(),
    log4j)));
Reproduce answered 1/3, 2017 at 6:9 Comment(2)
Just an FYI for this one - be careful using "log4j2-test.xml" for testing things. If this is in any of the folders log4j2 checks it will use it over "log4j2.xml" and make you think your overriding of this worked, when it actually didn't. I haven't tried your code, but I had this problem with a previous code snippet. I was using "log4j2-test.xml" thinking everything was overriding at runtime, only to find that it was overriding because log4j2 looks for "log4j2-test.xml" first, and then "log4j2.xml" logging.apache.org/log4j/2.0/manual/…Ramiroramjet
@Reproduce will it also work wit new CompositeConfiguration() instead of new XmlConfiguration()?Drank
O
0

I tried all the other solutions nothing worked for me.

tried Log4jServletContextListenerImpl extending Log4jServletContextListener @lonxx said able to write logs but not able to read environmental bean from spring context.

As log4j context is initializing before spring context initialization.

So Placed the below code in init(ServletConfig config) of InitServlet extends HttpServlet.

LoggerContext context = (LoggerContext) 
LogManager.getContext(false);
File file = new File("relativepath/log4j2/log4j2.xml");
context.setConfigLocation(file.toURI());

Now it's working.

using spring 5.3.22 & log4j2 2.17.2 and initservlet is configured in web.xml version ="2.5"

Outrigger answered 1/11, 2022 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.