Your comment says that "verbose" refers to the need to repeat this line of code in every class. My first response is that, in the big picture, adding two lines of code (variable definition plus import statement) to every class isn't that big a deal. Especially since you only need to add them to the classes that have behavior and therefore need to do logging. That said, the specific line of code that you're using is prone to copy-paste errors (more on that later).
But, since you want alternatives, here are a few, with reasons that you might or might not want to use them.
Use a single logger for the entire app
If you don't care about what class is reporting, or are willing to put all necessary context into the message, than a simple singleton logger will do the job:
LoggerSingleton.getInstance().debug("MyController is running")
In my opinion, one of the big benefits of a logging framework is having the context provided by separate logger instances -- if only to direct the log messages to different destinations. I wouldn't give that up just to save one line of code (you still need the import).
Plus, this increases verbosity at the point of use, which will end up in far more keystrokes.
Create your loggers at the point of use
I'm throwing this one out just because it eliminates the variable. I don't think I need to comment on it. Although it does show my preferred technique for getting a logger instance.
Logger.getLogger(getClass()).debug("blah blah blah");
Use a bean post-processor to inject the logger
Your example uses Spring, and Spring lets you hook into the bean initialization code. You could create a post-processor that inspects the bean for a logger
member variable, and creates a Logger
instance when it finds one.
While such a post-processor is only a few dozen lines of code, it's another moving part in your application, and therefore another potential source of bugs. I prefer to have as few of those as possible.
Use a mixin
Scala and Groovy provide traits, which let you encapsulate behavior. A typical Scala pattern is to create a Logging
trait, then add it to the class that needs logging:
class MyController with Logging
Unfortunately, this means that you have to switch languages. Unless you're using Java 8, in which case you can create a Logging
interface with a "default method":
public interface Logging {
default Logger getLogger() {
return Logger.getLogger(getClass());
}
}
Now, within your class code, you can simply use
getLogger().debug("blah blah blah");
While easy, this has a couple of disadvantages. For one thing, it pollutes the interface of every class that uses it, because all interface methods are public. Perhaps not that bad if you use it only for classes that are instantiated and injected by Spring, especially if you follow interface/implementation separation.
The bigger problem is that it has to look up the actual logger instance on every call. Which is fast, but unnecessary.
And you still need an import statement.
Move logger to a superclass
I'll repeat: I don't find repeated logger definitions verbose, but if you do I think this the best approach to eliminating them.
public abstract class AbstractController {
protected Logger logger = Logger.getLogger(getClass());
}
Now your controller classes inherit from AbstractController
, and they have access to the logger
variable. Remember that you have to put the @Controller
annotation on the concrete class.
Some people will find this a perversion of inheritance. I have tried to mollify them by naming the class AbstractController
rather than AbstractProjectClass
. You can decide for yourself whether or not there's an is-a relationship.
Other people will object to the use of an instance variable rather than a static variable. IMO static loggers are prone to copy-paste errors, because you have to explicitly reference the classname; getClass()
ensures that your logger is always correct.