Java Logging – Design Pattern for Wrapping Logging Around Execution

design-patternsjavalogging

Introduction

I am implementing a abstract Java class of a processing framework*. By implementing the function execute, I am able to add business logical functionality. I would like to add logging at the start and end of every implementation of every of my execute functions. Also in between some logging, if specific things are done. However, I would like to make this in a uniform manner. My thought was to inherit the framework class to an own new class which implements the logging and provides some new executeWithLogging functions, which are wrapping the logging around the specific parts. I am not sure if that is the best idea and whether I am able to use a design pattern that would make the whole endeavor elegant. How would I go on about the whole thing?

Challenges (please consider these!)

  1. One challenge in my case is that the original class has only one execute function, however, I'd need logging around multiple parts.
  2. The second thing is: Using a decorator pattern (was my first idea as well) does not quite work, if I am using also a execute, because the super.execute()-function would have to be called in the first line of my new execute(), isn't it?
  3. There would be at least 4 classes involved: BaseFunction from the framework, LoggingFunction extends BaseFunction from me, MyBusinessFunction extends LoggingFunction from me, MyBusinessClass which instanciates MyBusinessFunction.
  4. Not only do I need logging at the beginning and end of execute, but also in the middle.
  5. The "logging" is not just simple Java logging, but actually logging to a database. This does not change anything about the principles, but demonstrates that the logging might be more than just one line of code.

Maybe an example how I'd do the whole thing would be nice, to get me going.

|* A Storm Trident Function, similar to a Storm bolt, but this is not particularly important.

Best Answer

There are generally several possible ways to perform logging around a certain execution. First of all, it is good that you want to separate this, as logging is a typical example for Separation of Concerns. It truly doesn't make much sense to add logging directly into your business logic.

As for possible design patterns, here is a (non-conclusive) list from the top of my head:

  • Decorator pattern: A well-known design pattern, whereby you basically wrap the non-logging class into another class of the same interface and the wrapper does the logging before and/or after calling the wrapped class.

  • Function composition: In a functional programming language, you can simply compose your function with a logging function. This is similar to the decorator pattern in OO languages, but not a preferred way really, since the composed logging function would be based on a side-effecting implementation.

  • Monads: Monads are also from the functional programming world and allow you to decouple your execution and logging. This basically means you aggregate necessary logging messages and executions methods, but do not yet execute either. You can then process the monad in order to perform log-writing and/or actual execution of the business logic.

  • Aspect-oriented programming: More sophisticated approach, which achieves complete separation, as the class that does the non-logging behavior never directly interacts with the logging.

  • Relaying: Other standard design patterns may be suitable as well, for example, a Facade could serve as the logged entrypoint, before forwarding the call to another class which performs the business logic part. This can be applied to different abstraction levels as well. For example, you could log requests made to an externally reachable service URL, before relaying to an internal URL for actual non-logged processing of requests.

As for your added requirement that you need to perform logging "in the middle" - that's probably pointing to a strange design. Why is it, that your execute is doing so much, that something like a "middle" of its execution is even remotely of interest? If there is indeed such a lot of stuff going on, then why not bunch it up into stages/phases/what-have-you? You could in theory achieve logging in the middle with AOP I guess, but I'd still argue that a design change seems to be much more appropriate.