3

I am running a Java application in which I am invoking multiple threads, each with some unique names. Now I want to create multiple log files for each of them and the name of the log files should be as the thread names. Is this possible using log4j2. Please help me write log4j2 configuration files.

Thank you in advance.

Remko Popma
  • 32,719
  • 11
  • 84
  • 109
user1890780
  • 315
  • 1
  • 4
  • 5

2 Answers2

5

I agree a RoutingAppender is the way to go. I initially used the routing appender in conjunction with the ${ctx:threadName} lookup where the 'ctx' uses the ThreadContext. I found that I would have to sprinkle in the code a line like this:

ThreadContext.put("threadName", Thread.currentThread().getName());

While that code works it's not extensible in the design of the code. If I were to add a new java.lang.Runnable to the code base, I would have to also include that line.

Rather, the solution seems to be to implement the 'org.apache.logging.log4j.core.lookup.StrLookup' and register the @Plugin with the PluginManager Like this:

Class: ThreadLookup

package my.logging.package    
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.StrLookup;

@Plugin(name = "thread", category = StrLookup.CATEGORY)
public class ThreadLookup implements StrLookup {

@Override
public String lookup(String key) {
    return Thread.currentThread().getName();
}

@Override
public String lookup(LogEvent event, String key) {
    return event.getThreadName() == null ? Thread.currentThread().getName()
            : event.getThreadName();
}

}    

Configuration: log4j2.xml (packages attribute of the Configuration registers the @Plugin with the PluginManager)

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" packages="my.logging.package">
    <Appenders>
        <Routing name="Routing">
            <Routes pattern="$${thread:threadName}">
                <Route>
                    <RollingFile name="logFile-${thread:threadName}"
                    fileName="logs/concurrent-${thread:threadName}.log" filePattern="logs/concurrent-${thread:threadName}-%d{MM-dd-yyyy}-%i.log">
                    <PatternLayout pattern="%d %-5p [%t] %C{2} - %m%n" />
                    <Policies>
                        <SizeBasedTriggeringPolicy size="50 MB" />
                    </Policies>
                    <DefaultRolloverStrategy max="100" />
                </RollingFile>
            </Route>
        </Routes>
    </Routing>
    <Async name="async" bufferSize="1000" includeLocation="true">
        <AppenderRef ref="Routing" />
    </Async>
</Appenders>
<Loggers>
    <Root level="info">
        <AppenderRef ref="async" />
    </Root>
</Loggers>

Dan
  • 583
  • 1
  • 5
  • 8
2

This can be done with the RoutingAppender. The FAQ page has a good example config.

Remko Popma
  • 32,719
  • 11
  • 84
  • 109
  • I think RoutingAppender is suitable where we have some loggers previously defined and dynamically we have to choose the logger to which we want to dump the logs. But in my situation I have to create multiple loggers for each threads and the log file name will be based on the thread invocation time & the process ID or Thread name etc. Please help me with this. If this can be done using RoutingAppender then give some hints to proceed with this. Thank you – user1890780 Dec 04 '13 at 04:09
  • 1
    To be honest your requirements sound very complex. Is there not an easier way? But assuming you cannot control the design, I still think you can do what you describe with RoutingAppender. Please take another look at the RoutingAppender example in the FAQ. The last Route dynamically creates a log file with a name based on the ThreadContext value. The ThreadContext map has thread-local values so each thread can put some value based on the aspects you mentioned (time, pid, tid). This value then becomes part of the file name so you get a separate log file for that. – Remko Popma Dec 04 '13 at 21:34