在 Caliburn Micro .Net Core 3.1 中使用 Serilog

Using Serilog with Caliburn Micro .Net Core 3.1

我正在尝试将 Serilog 注入到我的 .NET Core 3.1 WPF 应用程序中的 classes 和项目中。

我正在使用 Caliburn.Micro 框架来处理 MVVM 方面的事情,Serilog Logger 已在 Bootstrapper class 中配置,我不清楚我是如何注册的记录器的实例,以便它可以在我的应用程序中用于 DI。

这就是我在 Bootstrapper class 中的内容,我在构造函数中添加了一个简单的 try-catch 来证明记录器已配置。

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);
    }


}

任何帮助或指向文档的指针都会很棒。

您将注册 Serilog 的 ILogger,就像在您的应用程序中注册所有其他单例一样,方法是在您的容器上调用 Singleton

_container.Singleton<ILogger, Log.Logger>();

在您的应用程序中使用 Serilog 记录器的另一种方法(我个人更喜欢)是从您的任何 类(ViewModel、服务等)访问 Log.Logger。使用 Log.ForContext<> 也很容易得到 contextual logger for every class,这在解决问题时很有用。例如

public class SomeViewModel
{
    private readonly ILogger _log = Log.ForContext<SomeViewModel>();
    // ...
}

public class SomeService
{
    private readonly ILogger _log = Log.ForContext<SomeService>();
    // ...
}

Log是静态的,Logger是静态的所以不需要注册,也不需要使用DI:

任何你使用 Log.Information("something");Log.Fatal("something"); 的地方都会进入你的日志文件。

public class SomeViewModel
{
    public SomeViewModel()
    {
       Log.Information("i am in somethingVM");
    } 
}

之后如果你想使用 DI,你必须使用这样的实例:(我使用 Caliburn 提供的接口 ILog 并创建封装 Logger 的 class Log..)

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
}

然后将 ILog 与 Log 绑定

 _container.Singleton<ILog, Log>();


public class SomeViewModel
{
    public SomeViewModel(ILog logger)
    {
       logger.Info("i am in somethingVM");
    } 
}

我不是 simplecontainer 方面的专家,但是如果你想在引导程序中调用记录器,你必须在像这样注册后将实例捕获到容器中(以测试):

IoC.Get<ILog>().Info("I am in boot");

通过这种编程方式,你可以做你想做的事,我已经将class日志与Serilog链接起来作为你的例子,但不需要使用它..


我使用 ninject,所以我们可以用它来解决这个问题:

        kernel.Bind<ILogger>().ToMethod(x => new LoggerConfiguration()
            .WriteTo.File(@"d:\toto.log")
            .CreateLogger());

那简化了绑定,但我不知道simplecontainer是否有这个功能,不需要声明class Log.

public class SomeViewModel
{
    public SomeViewModel(ILogger logger)
    {
       logger.Information("i am in somethingVM");
    } 
}

使用 simplecontainer 我看到了这个语法,但不确定它是否与 Ninject:

相同
        Container.RegisterHandler(typeof(ILogger), "Ilogger", x => new LoggerConfiguration()
            .WriteTo.File(@"d:\log.txt")
            .CreateLogger());