I'm trying to get Serilog to be injected into classes and projects within my .NET Core 3.1 WPF application.
I'm using the Caliburn.Micro framework to handle the MVVM side of things, the Serilog Logger has been configured in the Bootstrapper class, what I'm not clear on is how I register the instance of the logger so that it can be used for DI across my app.
This is what I have in the Bootstrapper class, I've added a simple try-catch
in the constructor to prove that the logger is configured.
public class Bootstrapper : BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public Bootstrapper()
{
Initialize();
try
{
Log.Information("In Bootstrapper Configure method");
}
catch (Exception ex)
{
Log.Fatal(ex, "The application failed to start correctly");
}
finally
{
Log.CloseAndFlush();
}
}
protected override void Configure()
{
_container.Instance(_container);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.File("log.txt")
.CreateLogger();
_container
.Singleton<IWindowManager, WindowManager>()
.Singleton<IEventAggregator, EventAggregator>()
_container
.PerRequest<IMyDataHandler, MyDataHandler>();
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.ToList()
.ForEach(viewModelType => _container.RegisterPerRequest(
viewModelType, viewModelType.ToString(), viewModelType));
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
return _container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
}
Any help, or pointers to documentation would be great.
Log is static,Logger is static so no need to register, neither to use DI:
anywhere you use Log.Information("something");
or Log.Fatal("something");
that will goes into your log file.
public class SomeViewModel
{
public SomeViewModel()
{
Log.Information("i am in somethingVM");
}
}
after if you want to use the DI, you have to use an instance like this: (i use the interface ILog which is given by Caliburn and create class Log which encapsulates Logger..)
public class Log : ILog
{
#region Fields
#endregion
private readonly ILogger logger;
#region Constructors
public Log()
{
logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.File(@"d:\log.txt").CreateLogger();
}
#endregion
#region Helper Methods
private string CreateLogMessage(string format, params object[] args)
{
return string.Format("[{0}] {1}",
DateTime.Now.ToString("o"),
string.Format(format, args));
}
#endregion
#region ILog Members
public void Error(Exception exception)
{
logger.Error(CreateLogMessage(exception.ToString()), "ERROR");
}
public void Info(string format, params object[] args)
{
if (Array.FindIndex(args, t => t.ToString().Contains("Something i dont want to log")) >= 0)
return;
logger.Information(CreateLogMessage(format, args), "INFO");
}
public void Warn(string format, params object[] args)
{
logger.Warning(CreateLogMessage(format, args), "WARN");
}
#endregion
}
and you bind ILog with Log
_container.Singleton<ILog, Log>();
public class SomeViewModel
{
public SomeViewModel(ILog logger)
{
logger.Info("i am in somethingVM");
}
}
i am not expert in simplecontainer, but if you want to call the logger inside the bootstrapper, you have to trap the instance in the container after having registered like this (to test):
IoC.Get<ILog>().Info("I am in boot");
With this way of programming, you do what you want, i have linked the class log with Serilog for your example, but no need to use it..
I use ninject, so we could to that with it:
kernel.Bind<ILogger>().ToMethod(x => new LoggerConfiguration()
.WriteTo.File(@"d:\toto.log")
.CreateLogger());
That simplify the binding, but i dont know if simplecontainer has this functionality, no need to declare class Log.
public class SomeViewModel
{
public SomeViewModel(ILogger logger)
{
logger.Information("i am in somethingVM");
}
}
with the simplecontainer i see this syntax, but no sure if its same thing than Ninject:
Container.RegisterHandler(typeof(ILogger), "Ilogger", x => new LoggerConfiguration()
.WriteTo.File(@"d:\log.txt")
.CreateLogger());