Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing org.apache.log4j.Logger without altering %C?

Tags:

java

log4j

To enable things like

logger.info("This is a formatted number: %.2f", number)

I decided to write a subclass of org.apache.log4j.Logger. I know, I could have written a wrapper class to achieve the same result but since I'm adding a lot of appenders to the logger at runtime I prefer to use inheritance.

The subclass looks like this:

public final class FormatLogger extends Logger {

private final static FormatLoggerFactory factory = new FormatLoggerFactory();

protected FormatLogger(String name) {
    super(name);
}

public static Logger getLogger(String name) {
    return Logger.getLogger(name, factory);
}

public void fatal(String formatter, Object... args)  {
    log(Level.FATAL, formatter, args);
}

public void log(Level level, String formatter, Object... args) {
    if (super.isEnabledFor(level)) {
        super.log(level, String.format(formatter, args));
    }
}
}

Everything works nicely - everything but one thing: the message text now adds the name of the logger subclass instead of the name of the class calling the logger. As pattern layout, I use the following format:

[%d{yyyyMMdd HHmmss}] %-5p [%t] %C: %m%n

i.e. things look like this:

[20110525 214515] INFO  [main] org.xyz.FormatLogger: This is a formatted number: 23.23

instead of:

[20110525 214515] INFO  [main] org.xyz.Main: This is a formatted number: 23.23

Is there some way to do such thing "properly" so that "%C" keeps printing the original class name?

like image 898
pruefsumme Avatar asked May 25 '11 20:05

pruefsumme


People also ask

Can you use log4j without Java?

log4j2 is a library that must be used by a running java process, to be vulnarable.

Can you disable log4j?

To disable log4j logging, set the logging level for the component to OFF in both log4j. conf and log4j.

What is difference between log4j and SLF4J?

Unlike log4j, SLF4J (Simple Logging Facade for Java) is not an implementation of logging framework, it is an abstraction for all those logging frameworks in Java similar to log4J. Therefore, you cannot compare both. However, it is always difficult to prefer one between the two.


2 Answers

I did something similar, but I ended up creating a wrapper and passing in the class name to it. Then with this class name I prepended it to the front of all the 4 logging levels which I was already wrapping anyway. It's quite messy, but I couldn't find another way of doing so. My logging statements now spit out the logger name then the package/class name. Its a bit cumbersome, but I'd rather have the extra information vs having not enough information.

like image 155
Joseph Avatar answered Nov 04 '22 13:11

Joseph


The solution is quite simple: add a fully qualified class name (FQCN), i.e.:

static String FQCN = FormatLogger.class.getName() + ".";

The log(..) method must then be modified like this:

super.log(FQCN, level, String.format(formatter, args), null);

This is perfectly shown in the example MyLogger.java that comes with log4j. -1 for my own laziness!

like image 35
pruefsumme Avatar answered Nov 04 '22 14:11

pruefsumme