sridhar
sridhar

Reputation: 1157

How to implement multi file appender in log4j2

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.

Upvotes: 1

Views: 2207

Answers (1)

Roger Gustavsson
Roger Gustavsson

Reputation: 1709

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.

Upvotes: 1

Related Questions