↓ Skip to main content

Log per class pattern.

··3 mins
Andrew Walsh
Author
Andrew Walsh
Coder with a passion for most all things technological.

Rookie Moves
#

Awhile ago, I had originally created a single logger for each service and shared it statically across the application.

public static class Log
{
  private readonly static Lazy<Log> instance = new Lazy<Log>(() => new Log(), true);
  public static Log Instance
  {
    get { return instance.Value; }
  }
}

It always had felt strange doing this since it violated encapsulation. I was referencing a static instance inside my objects without ensuring the existence of the log instance itself, while also making assumptions about the instance's state. Essentially reaching outside the class every time to the singleton, which is a global state instance in my case.

Best Practices
#

As I researched more on best practices with logging, logger per class appeared to be the best pattern since it offered the most fine grain control with respect to filtering and configuration.

When using logging in your class, you should separate the concern of how the log gets created from the use of the log. This can be achieved by having a factory accessor.

public class Log
{
  // Set your factory property to the actual log implementation you wish to use.
  public static Func<Type, Log> Factory { get; set; }

  // Instance based properties and methods.
}

You can also use the abstract factory pattern if you have to wrap your logging implementations.

public abstract class LogBase
{
  // Set your factory property to the actual log implementation you wish to use.
  public static Func<Type, LogBase> Factory { get; set; }

  // Abstract properties and methods.
}

Then just call the factory by passing in the class type it is for.

public class SomeObject
{
  private static readonly LogBase log = Log.Factory(typeof(SomeObject));
}

The Difference
#

It may not seem like much of a change but subtle differences are happening:

  • Calling class can now communicate it's state to the log's creation.
  • Log creation is no longer the responsibility, implicitly or otherwise, of the class.

In my case, this was very liberating since we had several log implementations in our large codebase. I no longer needed to worry about which log implementation was being used by messing with the singleton construction, and could leverage filtering when I need to isolate a single component or service that was causing trouble. Something that I couldn't do before.

More Reading & Resources
#

Related

Creating XML based templates in log4net.

·4 mins
Motivation # I decided to use log4net for a recent project I had been working on. There is a concept of loggers and appenders. Loggers are composed of appenders and a log threshold. Appenders are consumers of logging information and provide specific implementations (eg. file, email, event log, database). You can configure the loggers and appenders either in the application configuration or at runtime.

State behavioral pattern to the rescue.

··12 mins
The Creeping Problem # I recently found myself developing a request-response style system, where the lifetime of a request could be interrupted at any moment. For most same process execution, like your average desktop application, this is a concern, but arises more often when dealing with multiple coordinated processes. My case ended up being the latter.

Streaming UUEncoder in .NET.

·3 mins
Flashback # The last time I used Unix-to-Unix format (AKA UUEncoding) was when USENET was still the big thing and Mosaic web browser was just coming out. That was until recently, when I had a requirement to encode and decode this file type.