tags:

views:

1173

answers:

9

Every class that wants to use java.util.logging generally needs to declare a logger like this:

public class MyClass {
    private static Logger _log = Logger.getLogger(MyClass.class.getName());
}

How do you avoid this MyClass.class.getName() boilerplate code?

+2  A: 

You don't need getName() if you're using a 1.2+ version of log4j, getLogger() accepts a Class argument. But as for the rest, there isn't any way around it if you want each class to have a static log member with its own category.

sk
Other way around it other than writing an equivalent of getLogger that takes a Class and calls getName on it?
Tom Hawtin - tackline
You're not writing an equivalent, you're using the log4j method org.apache.log4j.Logger#getLogger(Class clazz) which has existed since log4j 1.2.
sk
A: 

You can shorthand this a tiny bit, as getLogger is overloaded to also just take the class. Like so:

public class MyClass {
    private static Logger _log = Logger.getLogger(MyClass.class);
}

The Logger can be as fleixble or inflexible as you want it to be. You can grab a new logger for each class, as in your example above, and have a hierarchy of loggers where you can controll and turn on/off the logging by class. Or if your project is small or a prototype, etc, you could just call Logger.getRootLogger() - but you'll lose the flexibility of fine-tuning what you log and don't log. You could have a base class where the logger lives, and have everyone call that one, but again, you lose some flexibility:

public class MyBase {
     protected static Logger _log = Logger.getLogger(MyClass.class);
}

public class MyClass extends MyBase {
    ....
    _log.info("Stuff....");
}

Bottom line, if you want to keep the ability to fine-tune configure your logging later in the project (turn on finer level debugging for just one class), then you may have to stick with the boilerplate in every class.

Ogre Psalm33
your base class is using the wrong class to create the logger.BUT, if you fixed it, wouldn't the sub class be logging against the superclass's logger?
davetron5000
A: 

If you make the logger nonstatic, you can at least inherit it:

public class SomeBaseClass
{
    protected Logger logger = Logger.getLogger(getClass());
}

public class SubClass extends SomeBaseClass
{
    public void doit() { logger.debug("doit!!!!"); }
}

That's how I've always done it.

davetron5000
Doesn't this log all messages against SomeBaseClass?
John Topley
No, getClass() will return the runtime class of an object
matt b
But code in the parent/superclass will log with the subclass's logger.
Steve Kuo
Inheriting for access to functionality is a Very Bad Idea
Bill K
+2  A: 

If you go for package-level loggers, with the addition of a boilerplate class per package, you can write:

private static final Logger log = Logs.log;

There are hacks to read the class name of the caller (in fact the logging implementation has a hack to detect the current method), but I wouldn't recommend that.

Tom Hawtin - tackline
+9  A: 

I have a template set up in Eclipse so that I only have to type a portion of the declaration, and then Eclipse will auto-complete the rest for me.

${:import(org.apache.log4j.Logger)}
private final static Logger log = Logger.getLogger(${enclosing_type}.class);
${cursor}

So, I only have to type logger, hit Ctrl+Space, followed by Enter, and Eclipse fills in the rest for me and adds the import declaration as well.

This won't cut down on the amount of boilerplate code, but at least it cuts down on the amount of keystrokes.

matt b
I just did this for JDE in Emacs. Thanks for the idea -- it'll at least minimize the physical pain of the boilerplate.
Steven Huwig
+3  A: 

Have a look at using point cuts in your code

I have not looked back since using them with spring.

Here is an article on using AspectJ

http://www.developer.com/java/other/article.php/3109831

Paul Whelan
+3  A: 

Depending on your logging needs, you could create a "LoggingService" class with static methods for logging to various "channels". I have found that I really don't need logging granularity down to the class level. You can name your loggers what every works best for you. We have been using this in large, enterprise applications for several years and the granularity has really not been an issue for us.

The logging service initialized in a static initializer block...so to log a message:

LoggingService.logError("blah");

No boilerplate code in each class.

Here is an example logging service:

public class LoggingService {

/**
 * A log for informational messages.
 */
static private Logger infoLog;

/**
 * A log for data access messages.
 */
static private Logger dataAccessLog;

/**
 * A log for debug messages.
 */
static private Logger debugLog;

/**
 * A log for error messages.
 */
static private Logger errorLog;

/**
 * A log for all XML related messages.
 */
static private Logger xmlLog;

/**
 * A log for all trace messages.
 */
static private Logger traceLog;

/**
 * A log for all warning messages.
 */
static private Logger warnLog;

static {

 //This is the bootstrap for the logging service.
 //Setup each logger
 infoLog = Logger.getLogger("com.company.logging.info");
 dataAccessLog = Logger.getLogger("com.company.logging.dataaccess");
 debugLog = Logger.getLogger("com.company.logging.debug");
 errorLog = Logger.getLogger("com.company.logging.error");
 xmlLog = Logger.getLogger("com.company.logging.xml");
 traceLog = Logger.getLogger("com.company.logging.trace");
 warnLog = Logger.getLogger("com.company.logging.warn");

 // This must be set so isErrorEnabled() will work.
 errorLog.setLevel(Level.ERROR);
 warnLog.setLevel(Level.WARN);
}
static public void logDataAccess(String pMessage) {
 dataAccessLog.info(pMessage);
}

static public void logInfo(String pMessage) {
 infoLog.info(pMessage);
}

static public void logDebug(String pMessage) {
 debugLog.debug(pMessage);
}

static public void logTrace(String pMessage) {
 traceLog.debug(pMessage);
}

static public void logWarn(String pMessage) {
 warnLog.warn(pMessage);
}

static public void logError(String pMessage) {
 errorLog.error(pMessage);
}

static public void logError(String pMessage, Throwable pThrowable) {
 errorLog.error(pMessage, pThrowable);
}

static public void logXml(String pMessage, XmlBean pContainer) {

 if (!xmlLog.isInfoEnabled()) return;

 xmlLog.info(pMessage + " : " + JAXBHelper.marshal(pContainer));
}

static public boolean isInfoEnabled() {
 return infoLog.isInfoEnabled();
}

static public boolean isDataAccessEnabled() {
 return dataAccessLog.isInfoEnabled();
}

static public boolean isDebugEnabled() {
 return debugLog.isDebugEnabled();
}

static public boolean isErrorEnabled() {
 if (errorLog.getLevel().toInt() >= Level.ERROR_INT) {
  return true;
 }
 return false;
}

static public boolean isTraceEnabled() {
 return traceLog.isDebugEnabled();
}

static public boolean isXmlEnabled() {
 return xmlLog.isInfoEnabled();
}

static public boolean isWarnEnabled() {
 return warnLog.isEnabledFor(Level.WARN);
}

}

Snowtoad
I guess that this might work for your needs, but I personally don't think that the client code would need to know if the xml log is enabled, or if the dataAccess log is enabled. Doesn't seem like a good interface to me. And why do you need separate loggers for each level? To each his own, I guess.
matt b
A: 

Take a look at SLF4J

bpapa
+1  A: 

Actually, the common practice of using class names for logger names is lazy more than anything.

The much better practice is to name loggers by the task context. This involves somewhat more thought process and planning but in the end, the result is much more meanigful granularity, where you can toggle logging levels for actual tasks rather than classes.

Roland Tepp
That's a good point. Though from a developer's standpoint, logging the actual class name is easier to use for debugging. When deployed to production and monitored, I think your suggestion is the best way to go.
Steven Huwig
Logging to the class name is a de facto standard for logging at a technical level. Using logical context is fine but I associate that more with logging as a business requirement, i.e. something like auditing.
Christoffer Soop