【问题标题】:Serilog and .NET Core 2.1 HostBuilder ConfigurationSerilog 和 .NET Core 2.1 HostBuilder 配置
【发布时间】:2018-11-16 15:01:07
【问题描述】:

我正在使用 .NET Core 2.1 HostBuilder 类来设置和运行 GRPC 服务器,但无法正确配置 SeriLog 以便它被 .NET Core 日志管道使用以及可用(通过依赖注入) 在我的应用程序的其他地方。

class Program
{
    private static async Task Main(string[] args)
    {
        var hostBuilder = new HostBuilder()
            .ConfigureServices((hostContext, services) =>
            {
                services.AddSingleton<ILogger>(BuildLogger);

                // other services here 
            })
            .ConfigureLogging((hostContext, loggingBuilder) =>
                loggingBuilder.AddSerilog(dispose: true));

        await hostBuilder.RunConsoleAsync();
    }

    private static ILogger BuildLogger(IServiceProvider provider)
    {

        // create a (global) logger
        Log.Logger = new LoggerConfiguration() 
            ...
            .CreateLogger();

        return Log.Logger;
    }
}

问题是我需要调用loggingBuilder.AddSerilog() 来使用上面几行在DI 服务配置中注册的单例ILogger

我意识到我可以直接调用 BuildLogger() 来获取 ILogger 实例并将该实例注册到 DI 服务配置中,但似乎我不应该这样做。我正在寻找一种方法,从.ConfigureLogging() 方法中访问ServiceProvider 实例,这样我就可以获得注册的ILogger 可能就像

serviceProvider.GetRequiredService<ILogger>();

并将其传递给AddSerilog() 调用。有什么想法吗?

【问题讨论】:

  • 我认为最好使用 ILogger 或 ILoggerFactory。我不是 ILoggerFactory 的忠实粉丝,但对我来说仍然比手动注入 ILogger 更好。第一个价格是 ILogger.
  • ILogger 默认未注册,而 ILogger 已注册,我认为这样就可以了。可悲的是,这不是很明显,人们往往会发现困难的方式。
  • @ThulaniChivandikwa ILogger&lt;T&gt; 是 Microsoft.Extensions.Logging 的一部分,而不是 SeriLog。
  • 我的回答是专门指 Microsoft.Extensions.Logging。默认情况下,可以解决的是 ILogger 和 ILoggerFactory 实现。我指出手动添加 ILogger(同样是 Microsoft.Extensions.Logging)不是一个好主意。
  • @ThulaniChivandikwa 我的问题是关于SeriLog.ILogger...

标签: c# serilog .net-core-2.1


【解决方案1】:

试试现在在 Serilog 中可用的新包 - https://github.com/serilog/serilog-extensions-hosting

  public static IHost BuildHost(string[] args) =>
    new HostBuilder()
        .ConfigureServices(services => services.AddSingleton<IHostedService, PrintTimeService>())
        .UseSerilog() // <- Add this line
        .Build();

【讨论】:

  • 感谢您的指点 - 该包确实是全新的。但我正在寻找的是一种在ConfigureServices() 中注册ILogger 实例,然后在UseSerilog() 调用中从DI 框架访问它的方法。默认行为依赖于静态全局 Log.Logger 实例,这违背了依赖注入的全部目的。
【解决方案2】:

我正在寻找一种方法,从 .ConfigureLogging() 方法中访问 ServiceProvider 实例,以便我可以获取已注册的 ILogger

您可以通过ILoggingBuilder.Services.BuildServiceProvider()ConfigureLogging() 方法中访问ServiceProvider。像这样:

//...

private static async Task Main(string[] args)
{
    var hostBuilder = new HostBuilder()
        .ConfigureServices((hostContext, services) =>
        {
            services.AddSingleton<ILogger>(BuildLogger);

            // other services here 
        })
        .ConfigureLogging((hostContext, loggingBuilder) =>
            loggingBuilder.AddSerilog(
                loggingBuilder
                    .Services.BuildServiceProvider().GetRequiredService<ILogger>(),
                dispose: true));

    await hostBuilder.RunConsoleAsync();
}

...//

【讨论】:

    【解决方案3】:

    这是一个示例,展示了如何执行此操作,包括使用 appsettings.json 配置 serilog,以及如何使用 ILogger 获取日志记录,而无需手动注入,如标记的答案所示,以及如何使用 IOptions:

        public class Settings
    {
        public string Sample { get; set; }
    }
    
    public class Service : IHostedService
    {
        private readonly ILogger<Service> _logger;
        private Settings _settings;
        public Service(ILogger<Service> logger,
            Settings settings)
        {
            _logger = logger;
            _settings = settings;
        }
    
        public Task StartAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    
        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
    
    class Program
    {
        static async Task Main(string[] args)
        {
            var host = new HostBuilder()
                       .ConfigureHostConfiguration(builder =>
                       {
                           builder.AddJsonFile("hostsettings.json", optional: true);
                       })
                       .ConfigureAppConfiguration((hostContext, builder) =>
                       {
                           builder.AddJsonFile("appsettings.json");
                           builder.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true);
                       })
                       .ConfigureLogging((hostContext, builder) =>
                       {
                           Log.Logger = new LoggerConfiguration()
                                        .ReadFrom.Configuration(hostContext.Configuration).CreateLogger();
                           builder.AddConfiguration(hostContext.Configuration.GetSection("Logging"));
                           builder.AddSerilog(dispose: true);
                       })
                       .ConfigureServices((hostContext, services) =>
                       {
                           var settings = hostContext.Configuration.GetSection("Configuration").Get<Settings>();
                           services.AddSingleton(settings);
    
                           services.AddHostedService<Service>();
                           services.AddLogging();
                           services.AddOptions();
                       })
                       .Build();
    
            using (host)
            {
                await host.StartAsync();
                await host.WaitForShutdownAsync();
            }
        }
    }
    

    【讨论】:

    • 这个最适合我使用新的 Worker 服务和 Serilog 的用例,谢谢
    【解决方案4】:

    根据 .NET Core 2.0+ 的 repo 文档,在提供的 loggingBuilder 上调用 AddSerilog() 并确保先配置 Serilog:

    //...
    
    private static async Task Main(string[] args) {
    
        Log.Logger = new LoggerConfiguration()
            //...
            .CreateLogger();
    
        var hostBuilder = new HostBuilder()
            .ConfigureServices((hostContext, services) => {        
                services.AddLogging(loggingBuilder =>
                    loggingBuilder.AddSerilog(dispose: true));
    
                // other services here 
            });
    
        await hostBuilder.RunConsoleAsync();
    }
    
    //...
    

    【讨论】:

    • 谢谢,但我正在寻找一种方法从 DI 框架中获取正确的 ILogger 实例,而不必使用全局 Log.Logger 实例。
    • @Mr.T 我认为您不了解扩展方法的作用。事实上,它确实将ILogger 包含在服务集合中,以便它可以用于 DI。这是它的唯一目的。它集成到 DI 框架的日志工厂中。他们只提到了Log.Logger,因为它是底层提供者,仍然需要先配置才能使一切正常运行。
    【解决方案5】:

    .Net6 中的一些变化

    这是我的程序.cs

    var builder = WebApplication.CreateBuilder(args);
    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    builder.Services.AddSingleton<WeatherForecastService>();
    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Information()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
        .Enrich.FromLogContext()
        .WriteTo.Console()
        .CreateLogger(); 
    builder.Host.UseSerilog( Log.Logger);
    var app = builder.Build();
    

    【讨论】:

      猜你喜欢
      • 2019-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-27
      • 2018-11-26
      • 2020-06-29
      相关资源
      最近更新 更多