11
votes

We have a modular application where modules have their own log4j logs (i.e. communication log and error log). The appenders and categories for these are all configured in the core log4j XML, but not all modules are always installed. The DailyRollingFileAppender creates its file regardless of use and that exposes the full set of modules although not present and as some of them are customer specific we'd like to hide logs not in use. Is there a way to make DailyRollingFileAppender create its file on first use instead of automatically at startup?

4
Why don't you exclude blocks for disabled components in the core XML? - newtover
We're deploying the log4j configuration oonce and then modules can be added later. As we leave the log4j details open for local changes we have a hard time modifying the file on later installs. And yes, we have a requirement of high level of install automation. - Mirvnillith

4 Answers

6
votes

I had the same problem, so I have extended the standard FileAppender class and I have created a new LazyFileAppender that is a FileAppender that lazily initialize the log file(creates it only when the first write operation happens).

The LazyFileAppender and some other additions to the standard log4j library can be found into a simple library that I have created : log4j-additions .

You can look at the source to develop your own extension or you can use it as is ...

4
votes

The file appenders have no option to lazily create the log files - the setFile method automatically creates the file if it doesn't already exist: ostream = new FileOutputStream(fileName, append);

You'll have to extend the appender and overwrite the file initialisation code yourself to get the behaviour you're after.

2
votes

In Log4j 2, both FileAppender and RollingFileAppender has the parameter "createOnDemand" which can be used to configure to create the log file only when a log event passed to the appender.

Example:

<RollingFile name="LogFile" fileName="test.log" filePattern="test-%i.log.gz" createOnDemand="true">
    <Policies>
        <SizeBasedTriggeringPolicy size="1MB"/>
    </Policies>
    <DefaultRolloverStrategy max="5"/>
</RollingFile>

More details here: https://logging.apache.org/log4j/2.x/manual/appenders.html#RollingRandomAccessFileAppender

0
votes

Extend the standard FileAppender class was unsuccessful for me. So I have found an other solution using appenders programmatically to create log files on demand only (and with timestamp in the name file). I have written these two methods :

public void startLog() {
    SimpleDateFormat sdf_long = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
    FileAppender fa = new FileAppender();
    fa.setName("foo");
    fa.setFile(sdf_long.format(new Date()) + ".log");
    fa.setLayout(new PatternLayout("%d{HH:mm:ss.SSS} %m%n"));
    fa.setThreshold(Level.DEBUG);
    fa.setAppend(true);
    fa.activateOptions();
    Logger.getRootLogger().addAppender(fa);
}

public void stopLog() {
    Logger.getRootLogger().getAppender("foo").close();
    Logger.getRootLogger().removeAppender("foo");
}

My log4j.properties file only configures the console appender. When I want to start logging I call the startLog() method. When I want to log in an other file I call stopLog() first and then startLog() method.