3

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.

Community
  • 1
  • 1
onkami
  • 8,791
  • 17
  • 90
  • 176
  • The name `LOGGER` does not conform to the Java naming conventions. All uppercase names are reserved for constant variables, or at least `final` variables pointing to immutable objects. – Lew Bloch Apr 23 '17 at 10:27
  • @LewBloch thank you for the reminder, any hope you also could help with the issue at hand? The question is not exactly about code styling. – onkami Apr 23 '17 at 10:31
  • This feels like an [XY Problem](https://meta.stackexchange.com/a/66378), can you please describe your reason for wanting a programmatic solution? – D.B. May 03 '17 at 03:00
  • @D.B. Very simple: I get an unknown (input) parameter of my program and I want a log file to include that parameter's value in log file name. – onkami May 03 '17 at 08:11
  • Thank you. By "parameter of my program" I assume you mean an argument passed into the `main` method, is that correct? – D.B. May 03 '17 at 16:06
  • @D.B. Exactly. Firthermore, the parameter is the name of the folder and the file (actually its name can be fixed) has to be created in the folder supplied at runtime. – onkami May 03 '17 at 20:40

1 Answers1

7

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.

D.B.
  • 4,523
  • 2
  • 19
  • 39