27
votes

I was wondering what some of the best practices were around logging and logging frameworks and dependency injection. Specifically, if I am designing a class that needs a way to log, how should I go about getting an interface to log to keeping dependency injection in mind?

Dependency injection seems to state that external dependencies should be injected from the outside (constructor or property setters), so should I take an ILog instance in the constructor and use in the class? Should I consider logging an optional dependency and get it in a setter? Am I pushing for too much flexibility by allowing for the logging interface to change and should I just take a hard dependency on a specific logging interface (by e.g. create a static ILog variable via a call to a factory method)? Could this factory method call into the container to get the ILog implementation or will this create initialization conflicts between static variables being initialization and the IoC container being initialized?

Should I be doing this:

public class MyService : ISomeService
{
  private static readonly ILogger s_log = 
            LoggingFactory.GetLogger(typeof(MyService))
  ...
}

or perhaps this:

public class MyService : ISomeService
{
  protected virtual ILogger Logger {get; private set;}
  public MyService(ILogger logger, [other dependencies])
  {
    Logger = logger;
  }
}

or even this:

public class MyService : ISomeService
{
  public virtual ILogger Logger {get; set;}
  public MyService()
  {
  }
}

Other patterns or ways to do this? What are people out there doing? What's working and when?

4
I would opt for the second or third options depending on whether or not having a logger for the service is considered critical.toad

4 Answers

4
votes

My advice? Wrap the logging interfaces into your own. I took a dependency on Log4Net once, got burned and had to refactor a lot of my projects because of it.

4
votes

It's great that you're looking into inversion-of-control and dependency-injection.

But for your question, there's another concept you might want to look into: aspect-oriented programming.

In .NET, there are some good frameworks available for doing aspect-oriented programming, including Castle, LinFu, and Microsoft's Policy-Injection Application Block. In fact, some inversion-of-control containers have some aspect-oriented features in them as well.

These concepts and tools help make concerns such as logging take a background seat in terms of code noise, and make be handled automagically.

3
votes

This won't be a complete answer, but one consideration will be that if you inject your ILog via your class' constructor you can then mock that logging framework for your unit testing. Other thoughts... A property setter for passing in the ILog means that you can't log actions from the constructor. Also, you don't know for sure if your instance even has an ILog available meaning you have to wrap every call with a test for a valid ILog instance.

0
votes

I would stick to injecting it and using an interface. Mainly to facilitate testing. Making it is easier to substitute a mock or stub when testing the consuming object.

I would base whether I used constructor or setter injection on the importance of the log to the consuming class. If you want it to be critical then I would favor constructor injection, if optional then setter.

I don't see where using a factory method couldn't work with the container, however, it then makes testing the consumer class dependent on a proper configuration of this factory method.