14

Taking an example of a simple Ruby on Rails application. It creates a Logger object during application load process:

# in environment.rb
config.logger = Logger.new(<STDOUT | file | whatever>)

# and in our application we use this object
logger.warn "This process is taking too long to process. Optimization needed."

My question is, why don't we use class methods (or static methods) for logging? Won't Logger.warn scale than Logger.new.warn? Or atleast Logger.warn seems intuitive than Logger.new.warn.

Even if Logger.new is a singleton object, what advantages does it offer?

17

Here's an example that uses Java. It's been a while since I've used log4j, but from what I remember, the whole log4j logging tool would initialize from an XML file. The XML file itself could contain multiple loggers with different configurations(where you write to, what levels are written, etc). So, in this case you would have logger objects rather than logger static methods in order to specify which logger you want to invoke. Ie.

Logger logger = Logger.get("Network");

would log things related to network connectivity, dropped packets, etc, or

Logger logger = Logger.get("Application");

which would log things related to your business logic/application. At least with log4j you could also configure which log levels actually get written out(info, trace, warn, error, debug being the default levels available).

If you had static methods, the best you could do is configure a single logger that would point to standard out, a file, etc, but everything you log would go to the same place. With logger objects, it's easier to make it so your logging information is spread out to multiple files.

  • Thanks. This also helped in understanding when to use static methods. – Harsh Gupta Jul 1 '15 at 5:59
  • 2
    While I prefer to instantiate an object to do my logging, as demonstrated here it's pretty common (I would say preferrable) to access it statically rather than passing it into every method call. Logging is just kind of global in nature. – Chad Schouggins Jul 2 '15 at 13:12
  • Also of note is that there's times in which we might want to configure the logger by extending it (or providing an implementation of some interface and providing that to the logger). This would be utilized to do something like change the logging destination (beyond what configuration files might allow). You'd probably make the specific instance static, though, as @ChadSchouggins mentioned. – Kat Jul 7 '15 at 19:03
2

Logger.new is a factory that will take where the result will be used (name of the class/file).

In the configuration files you can then decide what level to log to not logging at all for parts of the program without having to recompile the project.

Thus you can disable all but high-level logging (errors) for release builds and only activate the lowest level for the parts you are debugging.

2

Static method invocation should be avoided wherever possible. It's an antiquated alternative to proper Dependency Injection, and not something you'll find helpful in a larger codebase.

Consider testability, for example. Statically invoking logging puts the Subject Under Test in control of which logging class is used - there's no Inversion of Control. There is no possibility to inject a mock object or any kind of fake here. By injecting the logger into the SUT, you'll find that you have the option to mock the logger and inject it.

The benefits of using DI over the kind of static method invocation under discussion go beyond testability as well, of course. Consider what would happen if you wished to have two different loggers in your system, and the option to change the application behavior through configuration of the object graph alone, without editing existing code.

Overall, I'd suggest you try a DI approach, so you don't find your code untestable and unwieldy later.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.