2
votes

I have a Java application that runs for a few minutes each hour via a cron job (java -jar...). It runs in its own JVM, not in a continuously running environment like Tomcat. I am using Log4j 2.11 to do logging. Within the application, I have a particular logger with specific rollover requirements:

  1. Log to "rolling.log"
  2. At the end of each day (or on the first logging event of a new day), rolling.log should be rolled over to rolling-yyyy-MM-dd.log.gz and new logging events added to a fresh rolling.log.

I have not been able to get the rollover to work. All log messages are to "rolling.log" only and no rolling-yyyy-MM-dd.log.gz is ever created. To test this in the most simple way possible, I created a simple Java console application with the following two files. I would expect the log file to roll over on every execution as long as the system clock is showing a different minute, but this does not happen.

LoggingTest.java:

package log4jtest;

import java.time.Instant;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LoggingTest {

    private static final Logger logger = LogManager.getLogger();

    public static void main(String[] args) {
        System.out.println(Instant.now() + " - BEGIN: Logging to log4j");
        logger.error("Test log message");
        System.out.println(Instant.now() + " - DONE");
    }

}

log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configuration>
<Configuration status="WARN">
    <Appenders>
        <RollingFile name="RollingLogFile"
            fileName="logs/rolling.log"
            filePattern="logs/rolling-%d{yyyy-MM-dd-HH-mm}.log.gz"
            createOnDemand="true">
            <PatternLayout
                pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n" />
            <Policies>
                <TimeBasedTriggeringPolicy modulate="true"
                    interval="1" />
                <OnStartupTriggeringPolicy />
            </Policies>
            <DefaultRolloverStrategy />
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="error">
            <AppenderRef ref="RollingLogFile" />
        </Root>
    </Loggers>
</Configuration>

My guess is that since the JVM hosting the application and the Log4j instance is not running at the time the rollover would happen, then the rollover does not get triggered.

Ultimately, I abandoned the use of the RollingFileAppender and went with a straight-up FileAppender:

<File name="RollingLogFile" 
        fileName=logs/rolling-${date:yyyy-MM-dd}.log"
        createOnDemand="true">
    <PatternLayout
        pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n" />
</File>

This works, but it has a few disadvantages:

  1. I cannot monitor the simply named "rolling.log" (since it doesn't exist), but have to use the date-specific version of the filename.
  2. I cannot make use of log4j's compression on rollover features.
  3. I cannot make use of log4j's delete on rollover retention policies.

So, the question, restated, is: Using log4j, is it possible for an application executed in brief intervals to use a time-based log file rollover strategy in the same way that continuously running applications can?

2
Have you tried OnStartupTriggeringPolicy?ov7a
Yes, I did mention that I attempted OnStartupTriggeringPolicy in my post (sorry for the length). It doesn't appear to work with time-based file patterns.krallus
That's strange. Could you post your configuration with it? I've used it with Delete action of DefaultRollingStrategy and it worked for me in a similar case.ov7a

2 Answers

0
votes

Please, try the following configuration:

<RollingFile name="LogSpecial" 
        fileName="${sys:special.directory}/special.csv" 
        filePattern="${sys:special.directory}/special-%d{yyyy-MM-dd}.csv.gz" 
        createOnDemand="true">
    <CsvParameterLayout />
    <Policies>
        <TimeBasedTriggeringPolicy modulate="true" interval="1" />
        <OnStartupTriggeringPolicy />
    </Policies>
    <DefaultRolloverStrategy>
    <Delete basePath="{sys:special.directory}">
      <IfFileName glob="special-*.csv.gz" />
      <IfLastModified age="60d" />
     </Delete>
    </DefaultRolloverStrategy>
</RollingFile>

You can also switch on log4j2.debug system property to debug this configuration and investigate what's wrong.

0
votes

It turns out that log4j2 is capable of doing exactly what I was aiming for but part of my configuration, for unknown reasons, prevented it from working properly. The solution was to remove the createOnDemand="true" attribute from the RollingFile element. After excluding that attribute, the following configuration works exactly as I would expect (rolling over at startup, at most every minute):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configuration>
<Configuration status="WARN">
    <Appenders>
        <RollingFile name="RollingLogFile"
            fileName="logs/rolling.log"
            filePattern="logs/rolling-%d{yyyy-MM-dd-HH-mm}.log.gz">
            <PatternLayout
                pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n" />
            <TimeBasedTriggeringPolicy />
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="error">
            <AppenderRef ref="RollingLogFile" />
        </Root>
    </Loggers>
</Configuration>