In an earlier post I described some thoughts on tracing and applying it using interception to utilize AOP for tracing and instrumenting application objects without cluttering them with tracing code.
Mentioned also that there is another type of logging needed which is not just tracing of method calls and parameter, but it is custom logging to log verbose information or custom details to be shown in logs.
For this type of logging there are many options, you may inject the logger interface in constructor of your target classes which will introduce a dependency to logging interface polluting the constructor of the target classes while logging is infrastructural aspect which should not be a dependency in that explicit way.
public class OrderService : IOrderService
{
private readonly IOrderRepository _orderRepository;
private readonly IOrderValidator _orderValidator;
private readonly ILogger _logger;
public OrderService(IOrderRepository orderRepository, IOrderValidator orderValidator, ILogger logger)
{ ... }
public void PlaceOrder(Order order)
{
// ...
_logger.Info("Placing Order ...");
// ...
}
//...
var orderService = new OrderService(orderRepository, orderValidator, new TextLogger());
orderService.PlaceOrder(myOrder);
Another option would be to use Service Locator which is debatable to be anti-pattern, although in this case it should not be an anti pattern when used for logging as logging is not a dependency to be accidentally hidden by service locator, but it will introduce the service locator back door in the application which will engage developers to use it for resolving other dependencies as well.
public class OrderService : IOrderService
{
private readonly IOrderRepository _orderRepository;
private readonly IOrderValidator _orderValidator;
public OrderService(IOrderRepository orderRepository, IOrderValidator orderValidator)
{ ... }
public void PlaceOrder(Order order)
{
// ...
ServiceLocator.Resolve.Info("Placing Order ...");
// ...
}
//...
var orderService = new OrderService(orderRepository, orderValidator);
orderService.PlaceOrder(myOrder);
A better approach than Service Locator could be used for logging which is Static Factory, this way the factory will be limited and strongly typed for Logging and developers can not use it for resolving other dependencies.
public class OrderService : IOrderService
{
private readonly IOrderRepository _orderRepository;
private readonly IOrderValidator _orderValidator;
public OrderService(IOrderRepository orderRepository, IOrderValidator orderValidator)
{ ... }
public void PlaceOrder(Order order)
{
// ...
LoggerFactory.GetInstance().Info("Placing Order ...");
// ...
}
//...
var orderService = new OrderService(orderRepository, orderValidator);
orderService.PlaceOrder(myOrder);
Coming across this post by Simon about Supporting inversion of control in framework and after a small conversation with Mark he opened my eye to using decorator pattern to wrap around the class which needs to be logged using a logging decorator.
This way you explicitly hide the logging dependency using a decorator and leave your regular services and classes clean.
public class LoggedOrderService : IOrderService
{
private readonly IOrderService _orderService;
private readonly ILogger _logger;
public LoggedOrderService(IOrderService orderService, ILogger logger)
{ ... }
public void PlaceOrder(Order order)
{
_logger.Info("Placing Order ...");
_orderService.PlaceOrder(order);
}
}
//...
var orderService = new OrderService(orderRepository, orderValidator);
var loggedOrderService = new LoggedOrderService(orderService, new TextLogger());
loggedOrderService.PlaceOrder(myOrder);
Of course you still have a dependency between decorated class and logging interface but this time it is an explicit dependency as the decorated class is all about logging version of the original class this way it would be suitable to put the logging interface as dependency in the constructor for injection. also note that the decorator constructor will just need two parameters one for taking the original instance to be decorated and the other would be the logging interface so no chance to clutter the constructor with many parameters.
So for me as a conclusion I would implement a tracing interceptor for automatically inject tracing info (the AOP style), and if needed to log custom information I would wrap a logging decorator around the target class.

