Daschifahrer
Daschifahrer

Reputation: 50

How to set log4j.property to .jar location

I'm Setting up Log4j2 in a Spring-boot application. I now want to create a /log directory exactly where the .jar file is located.

This is needed as we start the java application from a startup script and the configuration should work on both windows and unix developer machines as well as a server.

I already tried with:

<RollingFile name="FileAppender" fileName="./logs/mylog.log" 
             filePattern="logs/mylog-%d{yyyy-MM-dd}-%i.log">

which just creates a log folder at the directory where the jar gets started.

then I read i should use .\log/mylog.log as .\ points to the directory of the jar file. But then it just creates a folder called .\log.

I also tried with configuration with jvm arguments and calling them at the log4j2.xml with: ${logFile}. Now a directory gets created called '${logFile}.

The only ${} command working is the directory of the log4j configuration file. But as this is inside the jar it just gets me a pretty useless folder structure

Thanks in Advance

EDIT: In the End what I did was setting up two configuration files, log4j2.xml and log4j2-prod.xml The log4j2.xml took the system property as Vikas Sachdeva mentioned, while the prod.xml got the location hard coded. Not really the solution I was looking for but made it work.

Upvotes: 2

Views: 395

Answers (2)

lo-fi wi-fi
lo-fi wi-fi

Reputation: 109

log4j2.xml:

<Properties>
    <!-- note trailing /.. -->
    <Property name="log.dir" value="${sys:java.class.path}/.."/>

    <Property name="fileName" value="${log.dir}/logs/logs.txt"/>
    <Property name="filePattern" value="${log.dir}/logs/$${date:yyyy-MM}/logs-%d{MM-dd-yyyy}-%i.txt"/>
</Properties>

...

<Appenders>
    <RollingFile name="rolling" fileName="${fileName}" filePattern="${filePattern}">
        ...
    </RollingFile>
</Appenders>

java.class.path system property points to jar file location WHEN it is ran via java -jar .jar like in the OP's case.

Pay attention, it will be broken for IDE or build tools' runs as they launch not a jar, but classes with other jar dependencies. For them, it has to be changed to cwd <Property name="log.dir" value="."/> or any other path


It is feasible to mitigate the build tool runs with Programmatic API though. And, in general, use it when you need custom dynamic resolving mechanism


public static void main(String[] args) {
    // call before log statements
    Log4j2OverridingLogConfigurationFactory.initialize();
    ...
}

public class Log4j2OverridingLogConfigurationFactory  {

    public static void initialize() {
        ConfigurationFactory factory = ConfigurationFactory.getInstance();
        AbstractConfiguration defaultConventionalConfig = (AbstractConfiguration) factory.getConfiguration(null, null, null);
        AbstractConfiguration overridingConfig = ConfigurationBuilderFactory.newConfigurationBuilder()
                .addProperty("log.dir", System.getProperty("log.dir", JarUtils.getLocation().toAbsolutePath().normalize().toString()))
                .build(false);
        Configurator.initialize(new CompositeConfiguration(Arrays.asList(defaultConventionalConfig, overridingConfig)));
    }

}

public class JarUtils {

    public static Path getLocation() {
        String protocol = JarUtils.class.getResource(JarUtils.class.getSimpleName() + ".class").getProtocol();
        if (protocol.equalsIgnoreCase("jar")) {
            return getApplicationLocationForJarLaunch();
        }
        // here, protocol = file
        return getApplicationLocationForClasspathBasedLaunch();
    }

    public static Path getApplicationLocationForJarLaunch() {
        return Paths.get(System.getProperty("java.class.path")).getParent();
    }

    public static Path getApplicationLocationForClasspathBasedLaunch() {
        return Paths.get(".");
    }

}

Upvotes: 0

Vikas Sachdeva
Vikas Sachdeva

Reputation: 5813

One solution is to pass log directory location through system properties.

Configuration file will look like -

<RollingFile name="FileAppender" fileName="${sys:basePath}/mylog.log" 
             filePattern="${sys:basePath}/mylog-%d{yyyy-MM-dd}-%i.log">

Now, pass VM argument basePath with absolute path of directory containing JAR file -

java -jar myapp.jar -DbasePath=/home/ubuntu/app

Upvotes: 1

Related Questions