Pregunta

In a project, I'm using slf4j with log4j as the underlying logging library. I want my log events to have the package and class name where the event was registered. Something trivial like: com.project.MyClass.

I know that, normally, I can use the %c or %C conversion characters to achieve this, but in this specific situation I can't. My log events must show some fixed number of values in a specific format. I didn't wanted to write that specific format in each call I would do to the logger, so I've created a wrapper class that contains the Logger as a static variable. In this wrapper class I've created the necessary methods to log in the adequate format, like info, debug and error. Here is a sample of the code:

    public final class AppLog {
        private static final Logger APP_LOGGER = LoggerFactory.getLogger("ApplicationLogger");

        public static void info(String... args) {
            AppLog.APP_LOGGER.info(LogsUtils.generateLogString(args));
        }
        ...
    }

The problem is that, when using the %c or %C conversion characters, they always output the com.project.WrapperClass as the classes that logged the event. Considering the code above: My AppLog class is in the Utils package. My log events always print Utils.AppLog as the package and class where the log was registered, but I wanted it to print the class name that called my AppLog class. It always prints:

2014-04-04|10:57:16,057|ERROR|utils.AppLog
2014-04-04|10:57:16,060|ERROR|utils.AppLog
2014-04-04|11:11:04,708|INFO |utils.AppLog

and I wanted this

2014-04-04|10:57:16,057|ERROR|com.project.domain.Person
2014-04-04|10:57:16,060|ERROR|com.project.dao.PersonDAO
2014-04-04|11:11:04,708|INFO |com.service.PersonService

One solution to fix this is injecting the class.getName() in each call to the info method in my wrapper class. But this seems like a very dirty solution for me. Is there any other solution to solve my problem that I'm not seeing?

Log4j configuration:

log4j.appender.APPLICATION=org.apache.log4j.DailyRollingFileAppender
log4j.appender.APPLICATION.file=${log.path}application.log
...
log4j.logger.ApplicationLogger=DEBUG, APPLICATION  
log4j.additivity.ApplicationLogger=false

Thanks in advance.

¿Fue útil?

Solución

UPDATED ANSWER :

Sorry I didn't get the question right. My previous answer was completly wrong;

So your problem here is that you are instanciating the logger (with LoggerFactory) with always the same name ApplicationLogger. There is no way from this logger to find the calling class of the AppLog object because there is not reference to it. As you say, you can inject the logger name in each call but it will be hard to maintain.

What you can try is wrapping the Logger class.

public final class AppLogger {

    private Logger logger;       

    protected AppLogger(String  loggerName) {
         this.logger = LoggerFactory.getLogger(loggerName);
    }

    public static AppLogger getAppLogger(String loggerName) {
         return new AppLogger(loggerName);
    }

    public void info(String... args) {
        this.logger.info(LogsUtils.generateLogString(args));
    }
    ...
}

In each class, do not use the LoggerFactory but your own class.

private static final AppLogger APP_LOGGER = AppLogger.getLogger(CallingClass.class)

and then log like this

APP_LOGGER.info("message");

Then in your pattern layout use %c (and not %C) and it should work as expected !

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top