Add file logging dynamically at runtime with Log4j

2019-04-13 03:46发布

问题:

I am in need of adding programmatically a file logging, with file name generated dynamically.

My code is like this:

private static final Logger LOGGER = LogManager.getLogger(Archiver.class);

public static void openLogfile(String folder) {
    String dateTime = "TODO";
    String fileName = folder + "upload" + dateTime + ".log";
    LOGGER.info("Opening " + fileName + " for logging.");
    // setting up a FileAppender dynamically...
    final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    final Configuration config = ctx.getConfiguration();
    Layout layout = PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, null, config, null,
            null, true, true, null, null);
    Appender appender = FileAppender.createAppender(fileName, "false", "false", "File", "true",
            "false", "false", "4000", layout, null, "false", null, config);
    appender.start();
    config.addAppender(appender);
    AppenderRef ref = AppenderRef.createAppenderRef("File", null, null);
    AppenderRef[] refs = new AppenderRef[]{ref};

    LoggerConfig loggerConfig = LoggerConfig.createLogger(true, Level.DEBUG, "org.apache.logging.log4j", "", refs,
            null, config, null);

    loggerConfig.addAppender(appender, null, null);
    config.addLogger("org.apache.logging.log4j", loggerConfig);
    ctx.updateLoggers();

}

I took a look at the recipe How to add Log4J2 appenders at runtime programmatically? and to http://logging.apache.org/log4j/2.x/manual/customconfig.html#AddingToCurrent.

My problems are:

  • The example on the log4j2 doc stated above would not compile, it is outdated, had to add few parameters without much idea what they are, usually I added nulls.
  • The very methods used in the documentation are now deprecated;
  • The file is being created but no logs appear there albeit having output on the console, and after program is quit, nothing is flushed in the file either.

Could somebody please provide a descent example with a most recent API to log4j2 to dynamically add file logging? I use org.apache.logging.log4j 2.8.1.

回答1:

Based on additional information in the comments, here is my suggestion. I don't think you need to do this programmatically for all the reasons you mentioned in your question.

Instead you can configure the log4j2 system using something like the following example. Note that you do not necessarily need the console appender I simply used that for testing.

log4j2.xml content:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="[%date{ISO8601}][%-5level][%t] %m%n" />
        </Console>
        <File
            fileName="logs/${ctx:fileName}.txt"
            name="logFile">
            <PatternLayout>
                <Pattern>[%date{ISO8601}][%-5level][%t] %m%n</Pattern>
            </PatternLayout>
        </File>
    </Appenders>
    <Loggers>
        <Logger name="example" level="TRACE" additivity="false">
            <AppenderRef ref="STDOUT" />
            <AppenderRef ref="logFile" />
        </Logger>
        <Root level="WARN">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

Java code:

package example;

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

public class LogFileNameBasedOnArg0Main {

    public static void main(String[] args) {
        ThreadContext.put("fileName", args[0]);
        Logger log = LogManager.getLogger();
        log.info("Here's some info!");
    }

}

Output:

I used a program argument of "myFile" which generated the file: logs/myFile.txt with the following content:

[2017-05-03T11:20:37,653][INFO ][main] Here's some info!

You should be able to modify this example to meet your needs and you won't have to do any programmatic configuration thus avoiding the issues you mentioned.