1

I am migrating my application from log4j to log4j2. Please find below the class which takes input (say mode is mode1) from the application current thread and appends it to the log file name (say log_mode1.log) and creates the appender and updates the log files.

Class:

public class MultiFileAppender extends AppenderSkeleton {
    ...

@Override
    protected void append(LoggingEvent event) {
     ...
}
@Override
    public void close() {
}
@Override
    public boolean requiresLayout() {
     ...
 }
}

Appender content in log4j.xml:

<appender name="TEST_MULTIFILE" class="com.test.it.logging.MultiFileAppender">
<param name="File" value="${LOGS}/test/test_%id%.log"/>
<param name="Append" value="true"/>
<param name="MaxFileSize" value="500KB"/>
<param name="MaxBackupIndex" value="5"/>
<param name="Encoding" value="UTF-8"/>
</appender>

How to get these parameters in java and create multi file appender like the above configuration in log4j2 ? Please help. Thanks.

sridhar
  • 1,117
  • 5
  • 31
  • 59
  • May I ask what is the purpose of this `MultiFileAppender`? By the name it sounds as if you want to write the same log entry to more than one file. If so, you don't need a custom class to do it, it can be done with configuration of the standard appenders in both log4j and log4j2. But maybe you have a special requirement that couldn't be solved? – Roger Gustavsson Oct 05 '15 at 13:27
  • Many thanks for the response. There are different modes (say mode1, mode2, mode3.. ) will be obtained from current running thread and the log content goes to the appropriate log file whose name contains the mode (say test_mode1.log). – sridhar Oct 07 '15 at 06:12
  • Can you create a different `Logger` object name based on the mode and use that to control which file to write the log statement to? If you normally do `LogManager.getLogger()` to get logger called `my.package.Test`, you could do `LogManager.getLogger(Test.class.getName() + ".mode1")` to get a logger called `my.package.Test.mode1` and so on. – Roger Gustavsson Oct 07 '15 at 07:03
  • thanks for response.. roger. In this case, mode inputs are dynamic. so, I believe this cannot be achieved by LogManager.getLogger(Test.class.getName() + ".mode1"). Please confirm my understanding. – sridhar Oct 07 '15 at 11:12
  • I can add an answer (instead of these comments) but it will be an answer on what I *think* your problem is. Perhaps you can edit your question describing your initial problem? Leave most of the current question at the end as a description of what you have tried. – Roger Gustavsson Oct 07 '15 at 11:33

1 Answers1

1

Take the following scenario:

A class is instantiated several times with a different id for each instance. Logging for respective id should go to it's own file. One file for each id. The values for id is not known when writing the code (it of course is when writing the Main class in this example).

public class Test implements Runnable {
    private static final Logger LOG = LogManager.getLogger();
    private final String id;

    public Test(String id) {
        this.id = id;
    }

    @Override
    public void run() {
        ThreadContext.put("id", id);    //org.apache.logging.log4j.ThreadContext
        while (true) {
            try { Thread.sleep(10000); } catch (InterruptedException e) { break; }
            LOG.info("{}: I have been sleeping for 10 seconds", id);
        }
    }
}

public class Main {
    private static final Logger LOG = LogManager.getLogger();

    public static void main(String[] args) {
        LOG.info("Starting thread 1");
        Thread t1 = new Thread(new Test("mode1"));
        t1.start();
        LOG.info("Starting thread 2");
        Thread t2 = new Thread(new Test("mode2"));
        t2.start();
        LOG.info("Starting thread 3");
        Thread t3 = new Thread(new Test("mode3"));
        t3.start();
    }
}

The following is the configuration for log4j2.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
    <Appenders>
        <Routing name="Routing">
            <Routes pattern="$${ctx:id}">
                <!-- If a special id should be treated differently
                <Route key="mymode">
                    ...
                </Route> -->
                <!--  Threads that don't have the id value set -->
                <Route key="$${ctx:id}">
                    <File name="File"
                            fileName="normal.log">
                        <PatternLayout pattern="%d{HH:mm:ss} [%p] %c %msg%n" />
                    </File>
                </Route>
                <!-- Threads with the id value set, and is not one of the special ones above -->
                <Route>
                    <File name="File-${ctx:id}"
                            fileName="id-${ctx:id}.log">
                        <PatternLayout pattern="%d{HH:mm:ss} [%p] %c %msg%n" />
                    </File>
                </Route>
            </Routes>
        </Routing>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Routing" />
        </Root>
    </Loggers>
</Configuration>

The idea for this is taken from the log4j2 FAQ. Also see Lookups.


If you still need to get your custom appender to work with log4j2, maybe this question with answer gives you some good hints on how to proceed.

Community
  • 1
  • 1
Roger Gustavsson
  • 1,689
  • 10
  • 20
  • Thanks for the response.. Roger. But, modes are dynamic and not constants. Those values are obtained from the current running thread. Hence, mode is used as a place holder or variable in log42.xml in appender definition and need to replace and create a appender log file in java. – sridhar Oct 08 '15 at 05:25
  • There's another method that I will update my answer with shortly. – Roger Gustavsson Oct 08 '15 at 05:30
  • Roger's answer is correct. The final Route above IS dynamic - a new file appender will be created for each distinct value of id and only events that have that key get written to it. – rgoers Oct 09 '15 at 06:24
  • @rgoers: sridhar's first comment relate to the first version of my answer. My answer has been edited since then. My first answer didn't handle it dynamically. – Roger Gustavsson Oct 09 '15 at 06:28