I am confused right now, and maybe does not understand the real problem.
I have an object which require logger instance to log error data.
for example
public class CommonFileSaver : IFileSaver
{
private static ILog _log = LogManager.GetLogger();
.....
}
I wish to test the logging process. And my current decission is to use the mock of the ILog interface.
At this point I have decided to use Unity to resolve dependencies.
So the line
ILog _log = LogManager.GetLogger();
will look something like
ILog _log = Resolver.Instance.Resolve<ILoger>();
The question is how to setup the Unity container to return me new instance of the ILog object using LogManager factory.
Thank you.
P.S. ILog is the log4net interface, and the whole logging thing is implemented using log4net right now.
Maybe it is not correct in design, but using factory is possible in Unity...
_container = new UnityContainer();
_container.RegisterType<ILog>(new InjectionFactory(c => LogManager.GetLogger()));
The problem here is that you're not following the Hollywood principle. Static factory methods and singletons don't fit well with dependency injection. You should change your code, to inject your ILog factory:
public class CommonFileSaver : IFileSaver
{
public CommonFileSaver(ILogFactory logFactory)
{
_log = logFactory.GetLogger();
}
private readonly ILog _log;
.....
}
You could write a wrapper for log4net (something which imho is a good idea anyway). The wrapper would take care of creating the instances by using the log4net factory method and it would also make sure that the "Configure" method is called.
If you write a wrapper you might want to consider this information.
If the goal of what you are trying to achieve is to test the logging process with a mock ILog when I would suggest that you also mock the LogManager and set up an expectation on the GetLogger so that it will return the mock ILog.
Related
On the logging samples in the documentation, there is an example how to inject a logger into a controller:
public class TodoController : Controller
{
private readonly ITodoRepository _todoRepository;
private readonly ILogger _logger;
public TodoController(ITodoRepository todoRepository,
ILogger<TodoController> logger)
{
_todoRepository = todoRepository;
_logger = logger;
}
}
Does the DI framework create a new logger each time I inject a logger into something like here? Is there a better way?
This is easily answered by a look into the source. When you do services.AddLogging(), the default behavior is that ILogger<T> is registered as a singleton:
public static IServiceCollection AddLogging(this IServiceCollection services, Action<ILoggingBuilder> configure)
{
// …
services.TryAdd(ServiceDescriptor.Singleton<ILoggerFactory, LoggerFactory>());
services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));
// …
}
So no, ILogger<T> instances for a certain type T are kept around for as long as the application is running. So when injecting an ILogger<TodoController> into your controller, the same logger instance will be passed to it every time.
Of course this only applies to the logger, but not your controller itself. By default, controllers are activated outside of DI but effectively live with a scoped lifetime. So on every request, there will be a new controller instance; but that one will then get the logger instance from before.
To answer your last question, is there a better way? No. Apart from the fact that this behavior is already a good one (since there’s no need for new logger instances), the proper way to use logging is indeed to inject ILogger<T> into types T, so you get a properly categorized logger instance. There’s really no need to worry about the very thin logger here when there are so many way more expensive things going on in the background that you will likely never see ;)
Since the ILogger<T> is a singleton, its instance will be reused all throughout the application. Note that this will not have an effect on logging scopes. The ILogger<T> implementation that you use within your application is actually just a thin wrapper that forwards logging calls to the internal loggers (which are also effectively singletons). So the lifetime of ILogger<T> is actually not relevant since they do not keep any state at all.
The logging scopes themselves are persisted using an AsyncLocal which is a mechanism to keep state throughout the asynchronous call flow. That means that logging scopes will just “magically” work and not leak outside of the call flow just because some instances happen to be shared between multiple threads (or asynchronous flows).
When using LibLog, is it possible to assert calls to the logger? Given the wiki lists the following example for usage:
public class MyClass
{
private static readonly ILog Logger = LogProvider.For<MyClass>();
}
Here the logger is an implementation detail hidden from the consumer, which is most of the benefit of using this library. Such that the library consumer does not have to worry about how loggers are instantiated. Looking at this blog post:
http://dhickey.ie/2015/06/capturing-log-output-in-tests-with-xunit2/
It seems that a lot of boiler plate is added to capture the log output, I'm not entirely sure about the approach, given that it also uses a redirected Serilog output in the unit test, something that seems odd given the library should only rely on the logging abstraction?
The only options I can currently think of are:
Inject the logger - This probably would be odd for the consumer of the library, and each library then would carry it's own ILogger definition that needs to be injected, defeating the advantages of the abstraction.
Wire up to a real logging framework - Set the current LogProvider for LibLog to use Log4Net or similar, and then somehow try and inject a mock / stub Logger into Log4Net, and assert calls via proxy.
Any relatively simple way to assert calls to the logger would be appreciated, but I suspect parallel test execution would cause problems even if it was possible to assert calls on the above logger?
In the logging config for almost all loggers you can configure then to throw exception when log fail.
Sample from nlog
<nlog throwExceptions="true">
... your nlog config
</nlog>
But in the abstraction created by LibLog you lost this features
What I've done in my project:
I've created my LoggerFactory. It exposes same static methods as NLogger.
public class LoggerFactory
{
private static ILoggerFactoryStrategy _loggerFactoryStrategy = new DummyLoggerFactoryStrategy();
public static void Initialize(ILoggerFactoryStrategy loggerFactoryStrategy)
{
_loggerFactoryStrategy = loggerFactoryStrategy;
}
public ILogger GetLogger<T>()
{
return _loggerFactoryStrategy.GetLogger<T>();
}
....
}
Dummy strategy can write just to debug output or do nothing. Another strategy could look smth like:
public class LoggerFactoryStrategy : ILoggerFactoryStrategy
{
public ILogger GetLogger<T>()
{
//create LibLog instance instead with LogProvider.For<T>()
var nlogger = LogManager.GetLogger(typeof(T).Name); //create instance of NLogger
return new NLogLogger(nlogger);
}
}
And NlogLogger wrapper could be smth like
internal class NLogLogger : ILogger
{
private readonly Logger _logger;
public NLogLogger(Logger logger)
{
_logger = logger;
}
public void Debug(string message)
{
_logger.Debug(message);
}
public void Warn(string message, params object[] args)
{
_logger.Warn(message, args);
}
public void Info(Exception exception)
{
_logger.Info(exception);
}
......
}
When application starts I initialize it with proper strategy what uses NLogger under the hood.
If I want to test calls to logger I can use mocked strategy.
This approach lets you to remove references to logger library across your solution, except your root projects and lets you switch from one to another if you need in the future.
Also, this allowed us to use NLogger in PCL projects.
I'm developing a small Console Application, and I'm logging the transactions.
I applied the DI (Ninject) using the following code:
class Program
{
private static ILogger _logger;
private static IKernel kernel;
static Program()
{
kernel = new StandardKernel();
kernel.Bind<ILogger>().To<Log4NetWrapper().WithConstructorArgument<Type>(MethodBase.GetCurrentMethod().DeclaringType);
}
static void Main(string[] args)
{
_logger = kernel.Get<ILogger>();
try
{
_logger.Info("Initializing...etc " + i.ToString() + ": " + DateTime.Now);
}
//etc...
}
}
That works fine, but then I thought using Factory to achieve the same result in another class (for comparison):
public class TestLogFactory
{
private static readonly ILogger _logger =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void LogInfo(object message)
{
_logger.Info(message);
}
}
The second approach looks cleaner to me, and If i change implementation (replace the log implementation) I only have to change LogManager class, but in the first approach i need to change every class that injects the dependency. My question: is there any advantage when using the first approach in this scenario? I'm learning about DI that's why I'm trying to use it.
Thanks
That's not DI, it's actually a ServiceLocator . Your app is way to trivial to need DI, but in a real app DI means this
class MyClass
{
public MyClass(ADependency dep1,OtherDependency dep2){}
}
This means, the deps are injected into the object by a third party (manually or using a DI Container). Usually, these are services which will be automatically invoked by a framework which will use a DI Container as the object factory.
The Di container then inspects the dependencies and their dependencies and then constructs the object with all the required dependencies injected automatically.
A DI Container is a Factory, albeit one that you don't have to write, but only configure. However the objects should be designed to accept the needed dependencies via constructor and those deps should be abstractions. The DI part is the fact that your object doesn't manage the deps but it gets them injected.
When using a DI Container and things change, you'll need to change the container configuration but that's it.
I have an interface which is used in an MVC controller which gets some data. To keep it simple the interface so far looks something like this:
public interface IDataProvider
{
DataModel GetData();
}
I have appropriate unit tests for this interface where it is called in the action. However, in the real implementation this will call a web service which of course could throw an exception, therefore if it does I want to write a test to ensure that I log a message if an error occurs.
To do this I have a logger interface which is actually an interface to NLog called ILogger. I could do this:
public interface IDataProvider
{
DataModel GetData(ILogger logger);
}
This would allow me to run unit tests for the logger making it nice and simple. However, I don't think this is the right way of doing this because the logger is really unrelated to this method. Also, if I start adding other methods to this interface which I need logging for then I will have to include the logger in the parameter of all of those methods as well.
The best way I can think of right now is to include the logger in the constructor of my implementation which might look like this:
public class DataProvider : IDataProvider
{
private readonly ILogger _logger;
public DataProvider(ILogger logger)
{
_logger = logger;
}
public DataModel GetData()
{
// CODE GOES HERE
}
}
However this means that I cannot test the logger in my unit tests. What is the best way to achieve this so that I can keep the logger separate from the method and make it testable?
I'll appreciate any help, thanks.
EDIT:
I realise I missed out unit testing code here is what I mean:
At the moment I am ensuring that GetData is called in my action this way:
var controller = new DataController(_dataProvider.Object);
controller.Index();
_dataProvider.Verify(dataProvider => dataProvider.GetData());
What I'd like to do is the same but for the logger but only if an exception is thrown like this:
_dataProvider.Setup(dataProvider => dataProvider.GetData()).Throws<WebException>();
var controller = new DataController(_dataProvider.Object);
controller.Index();
_logger.Verify(logger => logger.ErrorException(It.IsAny<string>(), It.IsAny<Exception>());
Obviously logger would be given to data provider in the setup. I hope that makes a bit more sense.
You can try using the factory pattern.
What happens here is in your production code, you are getting the logger from a Factory. In this factory, it returns either your real logger, or a fake logger which is setup in your unit tests. To your production code, it makes no difference what-so-ever.
In your Unit Tests, you are using a fake logger created using Moq. This fake allows you to test that an interface method was called, in this case ILogger.Log(). This is done by using the .Verify method.
Try something like this:
ILogger.cs
public interface ILogger
{
void Log(string message);
}
LoggerFactory.cs
public static class LoggerFactory
{
public static ILogger Logger
{
get
{
return LoggerFactory._logger == null ? new Logger() : LoggerFactory._logger;
}
set
{
LoggerFactory._logger = value;
}
}
private static ILogger _logger = null;
}
DataProvider.cs
public void GetData()
{
var logger = LoggerFactory.Logger;
logger.Log("..."); // etc...
}
UnitTest.cs
private void Mock<ILogger> _mockLogger = null;
public void Load()
{
this._mockLogger = new Mock<ILogger>();
LoggerFactory.Logger = _mockLogger.Object;
}
public void UnitTest()
{
// test as required
this._mockLogger.Verify(m => m.Log(It.IsAny<string>()));
}
Use a mocking framework (e.g. Moq or RhinoMocks) to verify that the logger was called. Then the final code block you post, where the logger is passed in via the constructor, will work.
Passing logger (or any other dependencies) in constructor is very standard practice and allows you to use dependency injection framework if needed.
I'm not sure why you see passing logger in constructor as limiting for unit test: you have 3 components that you can test separately
controller (depends on data provide, mock this dependency to test),
data provider (depends on logging and some other classes that let you call web service - mock all dependencies so you know when logging called and no need to call Web service)
logging - not sure what it depends on, but should be testable separately.
Notes:
use mocking framework (i.e. moq ) for your tests - you'll be able to provide any implementations of interfaces (including exceptions) very easily.
see if dependency injection framework (i.e. Unity ) would work for you. MVC4 is very well suited for it.
If you need to test that the logger is being called, I suggest using a test double called a "spy". This would not do any logging, but keep track of which methods (if any) were called. Then you can verify that the logger is called in specific instances.
You could do this by using a mocking framework to create the double (or mock) for you. Or you could create the ILogger implementation yourself. For example:
class LoggerSpy : ILogger
{
public string LogWasCalled;
public void Log(string message)
{
LogWasCalled = true;;
}
}
The following seems to have an example of mocking an ILogger using Moq: How to Mock ILogger / ILoggerService using Moq
I am wrapping the patterns & practices Enterprise Library Logging Application Block for an application written in .NET.
I want to be able to subclass a logger (i.e to provide domain specific logging).
What is the best way to do this?
For e.g, I have a static Logger class at the moment, but this does not allow me to specialize it for domain specific logging.
For example,
Log(MyDomainObj obj, string msg)
Check out NLog. They use this sort of pattern:
private static Logger myDomainLogger = LogManager.GetCurrentClassLogger();
You can then specialize the output based on the class that myDomainLogger belongs to.
More detail:
class MyDomain
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private void SomeFunc()
{
_logger.Trace("this is a test");
}
}
Then in your output you can have it output "MyDomain.SomeFunc" as part of the "this is a test" message.
Also, checkout log4net. I never found the EL's logging to be as flexible as log4net. I chose log4net since I was already familiar with using log4j.
protected readonly log4net.ILog LOG = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Doing it this way, I can get logs like this:
2009-07-15 09:48:51,674 [4420] DEBUG
SampleNamespace.SampleClass [(null)] -
Sample message you want to output
You could even do better than that. Write a wrapper class that wraps either Nlog or log4net or whatnot. You can then use that wrapper class (maybe use an interface to it if you really want to decouple things) in your code. This way, if you decide to change logger class, you need to change just one class and not edit all your classes.