Which pattern to use for logging? Dependency Injection or Service Locator?
My little rule of thumb:
If it's in a class library, use either constructor injection or property injection with a null-object pattern.
If it's in a main application, use the service locator (or singleton).
I find this applies pretty well when using log4net. You don't want class libraries reaching out to things that might not be there, but in an application program, you know that the logger is going to be there, and libraries like log4net are based heavily around the service-location pattern.
I tend to think of logging as something sufficiently static that it doesn't really need DI. It's extremely unlikely that I'll ever change the logging implementation in an application, especially since every logging framework out there is incredibly flexible and easy to extend. It's more important in class libraries when your library might need to be used by several applications which already use different loggers.
YMMV, of course. DI is great but that doesn't mean everything needs to be DI'ed.
The logger is clearly a service that your business logic depends upon, and should thus be treated as a dependency the same way you do with IDependency
. Inject the logger in your constructor.
Note: even though AOP is mentioned as the way to inject logging I do not agree that it is the solution in this case. AOP works great for execution tracing, but will never be a solution for logging as part of business logic.
I personally do a mixture of both.
Here are my conventions:
- From a static context - Service Location
- From an instance context - Dependency Injection
I feel this gives me the right balance of testability. I find it a little harder to setup tests against classes that use Service Location than use DI, so this is why Service Location ends up being the exception rather than the rule. I'm consistent in its use, though, so it's not hard to remember what type of test I need to write.
Some have raised the concern that DI tends to clutter constructors. I don't feel this is a problem, but if you feel this way, there are a number of alternatives that use DI, but avoid constructor parameters. Here is a list of Ninject's DI methods: http://ninject.codeplex.com/wikipage?title=Injection%20Patterns
You'll find that most Inversion of Control containers have the same features as Ninject. I chose to show Ninject because they have the most concise samples.
Hopefully this is helpful.
Edit: To be clear, I use Unity and Common Service Locator. I have a singleton instance of my Unity container for DI and my implementation of IServiceLocator is simply a wrapper around that singleton Unity container. This way I don't have to do any type mappings twice or anything like that.
I also don't find AOP to be particularly helpful beyond tracing. I like manual logging better simply for its clarity. I know that most AOP logging frameworks are capable of both, but I don't need the former (AOP's bread and butter) most of the time. This is just personal preference, of course.
Maybe this will be little offtopic, but why do we need injecting logger at all, when we can just type at the beggining of the class:
Logger logger = LogManager.GetLogger("MyClassName");
Logger doesn't change during development and later during maintenance. Modern loggers are highly customizable, so argument
what if I want to replace text logger with database?
is missed.
I don't negate using dependency injection, I'm just curious about your mind.