0

I need to re-factor the log files for a major project. Currently all logs goes to the same file. This file grows over 100MB a day. The problem is that there is a lot of scheduled code running every 5 minutes that fills up the log file. The main goal of the re-factor is that all logs that is created due to a schedule goes into separate files.

Each class in the project has the following:

final static Logger logger = LoggerFactory.getLogger(MyClass.class);

It is simple to only change it like this in classes that runs scheduled:

final static Logger logger = LoggerFactory.getLogger("scheduledLogger");

The problem is that some classes are called from a scheduled class and a non scheduled class and the logging must go to the appropriate log file.

It simply not possible to change every single function call in the entire project to send on the appropriate logger. The current solution which I have thought of is to create a object adapter like follows:

public class LoggerAdapter implements Logger {

private Logger defaultLogger;

private Logger scheduledLogger1 = LoggerFactory.getLogger("scheduledLogger1");

private Logger scheduledLogger2 = LoggerFactory.getLogger("scheduledLogger2");

//.. there are about 10 scheduled loggers

public LoggerWrapper(Class<?> Clazz) {
        defaultLogger = LoggerFactory.getLogger(Clazz);
}

//Implement each function like so
public void debug(String s) {
        Logger logger = findLoggerToUse();
        logger.debug(s);
}

public void trace(String s) {
    Logger logger = findLoggerToUse();
    logger.trace(s);
}

//See if logging has been called from a scheduled class
private Logger findLoggerToUse() {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTraceElements) {
            String className = stackTraceElement.getClassName();
            if (fastStringCompare(className,SCHEDULED_CLASS_NAME_1)) {
                return scheduledLogger1;
            }
            if (fastStringCompare(className,SCHEDULED_CLASS_NAME_2)) {
                return scheduledLogger2;
            }
        }
        return defaultLogger;
    }

Then in each class in the entire project I only need to change:

private Logger logger = new LoggerAdapter(MyClass.class);

The problem with this is that trace(String s) prints a trace to LoggerAdapter instead of the actual caller. I would like to know if there is a better way of solving the whole overall problem or if there is a small fix for the trace calls.

Eduan Bekker
  • 411
  • 2
  • 7
  • 18
  • There is answer you are looking for: http://stackoverflow.com/a/7998071/4465354 . Mdc is just a threadlocal variable you need to push before scheduling – qwwdfsad Mar 25 '15 at 14:12

1 Answers1

0

Instead of changing the code everywhere, write a custom appender. I suggest you try to switch to slf4j with logback or log4j-2 before since both make writing custom appenders much, much more simple. slf4j has drop-in replacements for the old log4j API, log4j-2 has documentation how to migrate.

Now you need to write an appender which is controlled by a thread-local variable. slf4j and the old log4j call this "MDC", log4j-2 calls it "Thread Context".

You set this variable when the scheduler code starts and clear it when it ends. Everything executed in the same thread will eventually go through the appender which can examine the variable and route the messages to the correct file.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820