Using MDC in log4j for dynamic log file name

Is it possible how to use MDC for the log file name at runtime.

I have one web application that is being called by different names at the same time using tomcat docbase. Therefore, I need to have separate log files for each of them.

+6
source share
3 answers

This can be done in Logback , the successor to Log4J.

The reservation is intended as a successor to the popular log4j project, which collects where log4j does not work.

See the documentation for Sift Appender

SiftingAppender is unique in its ability to link and customize embedded applications. In the above example, there will be nested instances of FileAppender in SiftingAppender, each of which is identified by the value associated with the "userid" MDC key. Whenever a new value is assigned to the MDC "userid" key, a new FileAppender instance will be created from scratch. SiftingAppender tracks the applications it creates. Applicants not used for 30 minutes are automatically closed and discarded.

In this example, they generate a separate log file for each user based on the MDC value. Other MDC values ​​may be used depending on your needs.

+10
source

This is also possible with log4j. You can do this by implementing your own appender. I think the easiest way is to subclass AppenderSkeleton .

All logging events end in the append(LoggingEvent event) method, which you must implement.

In this method, you can access the MDC using event.getMDC("nameOfTheKeyToLookFor");

You can then use this information to open the file for writing. It may be useful to look at the implementation of standard applications such as RollingFileAppender to find out the rest.

I myself used this approach in an application to split logs of different threads into different log files, and it worked very well.

+9
source

For some time I struggled to find functionality similar to SiftingAppender in log4j (we could not switch to logback due to some dependencies), and the result was a software solution that works very well using MDC and adding loggers at runtime

 // this can be any thread-specific string String processID = request.getProcessID(); Logger logger = Logger.getRootLogger(); // append a new file logger if no logger exists for this tag if(logger.getAppender(processID) == null){ try{ String pattern = "%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n"; String logfile = "log/"+processID+".log"; FileAppender fileAppender = new FileAppender( new PatternLayout(pattern), logfile, true); fileAppender.setName(processID); // add a filter so we can ignore any logs from other threads fileAppender.addFilter(new ProcessIDFilter(processID)); logger.addAppender(fileAppender); }catch(Exception e){ throw new RuntimeException(e); } } // tag all child threads with this process-id so we can separate out log output MDC.put("process-id", processID); //whatever you want to do in the thread LOG.info("This message will only end up in "+processID+".log!"); MDC.remove("process-id"); 

The filter added above simply checks for a specific process identifier:

 public class RunIdFilter extends Filter { private final String runId; public RunIdFilter(String runId) { this.runId = runId; } @Override public int decide(LoggingEvent event) { Object mdc = event.getMDC("run-id"); if (runId.equals(mdc)) { return Filter.ACCEPT; } return Filter.DENY; } } 

Hope this helps a bit.

+5
source

Source: https://habr.com/ru/post/900680/


All Articles