Software Development

Logging Without a Static Logger

How do you organize logging in your applications? I mean web applications or command line apps, or even mobile apps. I bet you have some global variable or a singleton, known as Logger, which has a few methods like info(), error(), and debug(). You configure it when the app starts, or it configures itself via something like log4j.properties, and logs everything to the console or a file, or even a database. I was doing exactly that, or something very similar, for many years, until I finally realized how wrong this approach was. In one of my recent Ruby applications I did it all differently, and since then I’m much happier than I was before.

Static Logger

Well, if your application is simple and has almost no unit or integration tests, you will be doing just fine with a static logger, which in essence is a global variable. However, as we discussed before, global variables are evil. What can go wrong if we use a static logger? Or, in other words, as one of my friends used to say, what exactly is the problem we are going to solve? Basically, there are two problems:

  • First, with a single global logger you will have a hard time writing a unit test to check whether your app is actually logging things correctly. Even if you intercept the log stream, there will be a lot of noise, coming from other threads and other tests. It’s not an unsolvable problem, but its solution adds complexity to your tests.
  • Second, when you decide to show a selected part of the log to your end-user, you will have to do a lot of coding just in order to separate what belongs to the user and what does not, especially in a multi-threaded environment. You’re lucky if it’s Java and you have thread groups, but in Ruby, for example, there is no such thing and you will have to find some workaround.

To overcome them both, in Zold, a Ruby command line application, I decided to pass log as a variable to all classes that need any logging. In Ruby it’s easier than in Java, because they have optional parameters. Look at this class, for example (it’s a simplified version, of course):

01
02
03
04
05
06
07
08
09
10
11
12
13
class Zold::List
  def initialize(wallets:, log: Log::NULL)
    @wallets = wallets
    @log = log
  end
  def run
    @wallets.all.sort.each do |id|
      @wallets.acq(id) do |wallet|
        @log.info("#{id}: #{wallet.balance}")
      end
    end
  end
end

 

This class is supposed to list all wallets in the current directory and print their balances to the log, which in some cases will be the console. However, when this class is called from a web application, the destination of the print is a temporary file, which is later rendered on the web page. In unit tests it can be something else, which has to capture everything that is sent to the log and then delivered to the unit test.

As you see, the default value of the log is Log::NULL, which is the constant I had to define myself, as a default logger, which doesn’t log anything anywhere. By default, this class will log nothing. It will quietly check all the balances of all the wallets and print nothing. Well, it will print, but nobody will see that.

In a unit test I create an object with a few methods like debug(), info(), etc. and pass it to the instance of class Zold::List, which I’m testing. In other words, it’s a fake/mock version of the logger, which I use to capture everything that Zold::List sends out. Then I can check what’s there.

Am I saying obvious things here? If so, why do we still have static loggers everywhere in Java, Ruby, PHP, C#, etc? Anyway, I recommend you use an injectable logging dependency instead.

And yeah, by the say, I’m sure you noticed the change in the name. It’s not a logger anymore, it’s log. I’m sure you know why.

Published on Java Code Geeks with permission by Yegor Bugayenko, partner at our JCG program. See the original article here: Logging Without a Static Logger

Opinions expressed by Java Code Geeks contributors are their own.

Yegor Bugayenko

Yegor Bugayenko is an Oracle certified Java architect, CEO of Zerocracy, author of Elegant Objects book series about object-oriented programing, lead architect and founder of Cactoos, Takes, Rultor and Jcabi, and a big fan of test automation.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button