Where to define a static application-wide logger?
I have a number of packages in my Java w开发者_运维技巧eb application. In some of them I use this construct:
public class Foo {
private static Logger logger = LoggerFactory.getLogger("com.XXX");
public void bar() {
Foo.logger.debug("Method bar() was just called");
}
}
Of course, it's just an example. Everything works fine, but I don't like the idea of logger initialization in many classes. It's an obvious code duplication. I would like to move it to some helper class and let all other classes access it. Is it a correct idea? Or maybe there is some other "best practice" or a pattern?
Saying this is code duplication is like saying that having import java.util.*
in 75% of your classes is code duplication. Or that you find yourself writing public class ...
too often. It's not duplicating logic. It's duplicating boilerplate code.
Code duplication is only a design smell when it involves duplicating logic. If there is too much boilerplate code, that's a language design smell really. Nothing you should really be worried about.
On the downside, you lose the ability to fine-tune your logging if you abandon the hierarchal structure.
I don't think you will win anything if you do use centralised global static logger constrcut other than the common Log4J calls/inits.
If you write
private static Logger logger = LoggerFactory.getLogger("com.XXX");
logger.info("Hello World");
or anything like this
GlobalLogger.info(this, "LogMessage"); //Singleton...
...will not make your code more "readable".
You could write your own utility class which wraps the global logger and implements static delegates to the logger methods. Then just do a static import of this class:
public class MyLogger {
private static Logger logger = LoggerFactory.getLogger("application");
public static void debug(String s) {logger.debug(s));}
public static void debug(Class<?> caller, String s) {
LoggerFactory.getLogger(caller.getName()).debug(s);
}
// ...
}
Usage:
import static MyLogger.*;
public class Foo {
public void bar() {
// makes use of static import!
debug("Method bar() was just called");
debug(this.getClass(), "Method bar() was just called");
}
}
Added an overloaded version of the example debug
delegate which takes a class object and uses the appropriate Logger.
This is not recommended since you will lose the hierarchical logging capabilities of Log4j (if that is what you are using), where it is very beneficial to add different appenders at different levels of your package tree. I would not do this since you would lose information about which class created the log message.
Encapsulating a 3rd party dependency (i.e., Log4j) with a utility logger class makes sense.
For example, should a team decide to switch from Log4j to NextBigThingLogger, they simply update their MyLogger class, and none of the other application classes.
Cleaner, and easier maintenance.
Apache APIs, and even the Java language itself, are filled with "design smells" but that doesn't mean we should not respond to them.
I think you're after the Singleton design pattern. Not being a java programmer, I dug this up from google:
http://www.javacoffeebreak.com/articles/designpatterns/index.html
You can create an Adapter pattern for logger. In my case, I extended logger to include all the logger functionality. This is then made into a Singleton.
public class LoggerAdapter extends Logger {
private LoggerAdapter instance;
private Logger logger;
private LoggerAdapter() {
}
public static LoggerAdapter getInstance(Clazz<?> clazz) {
if (instance == null) {
instance = new LoggerAdapter();
}
instance.logger = logger = LoggerFactory.getLogger(clazz.getName());
return instance;
}
@Override
public void trace(Object object) {
logger.trace(object);
}
//Other overridden methods here...
};
Basically, a dynamic changing logger....
精彩评论