Serilog和.NET Core 2.1 HostBuilder配置

14
我正在使用.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<T>或ILoggerFactory。我不是ILoggerFactory的忠实粉丝,但对我来说仍然比手动注入ILogger更好。第一选择是ILogger<T>。 - Thulani Chivandikwa
ILogger默认情况下未注册,而ILogger <T>是已注册的,我认为这样做很好。不幸的是,这并不是非常明显,人们往往会通过艰难的方式发现它。 - Thulani Chivandikwa
@ThulaniChivandikwa ILogger<T> 是 Microsoft.Extensions.Logging 的一部分,而不是 SeriLog。 - Mr. T
我的回答特别针对 Microsoft.Extensions.Logging。默认情况下,可以解析 ILogger<T> 和 ILoggerFactory 实现。我指出手动添加 ILogger(同样是 Microsoft.Extensions.Logging)不是一个好主意。 - Thulani Chivandikwa
@ThulaniChivandikwa和我所关心的问题是关于SeriLog.ILogger的... - Mr. T
啊,是的,我的错误导致了错误的假设。 - Thulani Chivandikwa
5个回答

12

现在可在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();

3
谢谢指点 - 那个包确实是全新的。但我正在寻找的是一种在ConfigureServices()中注册ILogger实例并从DI框架中访问它,在UseSerilog()调用中使用它的方法。默认行为依赖于静态全局Log.Logger实例,这违背了依赖注入的初衷。 - Mr. T

9
我所要找的方法是,从.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();
}

...//

6
这是一个示例,展示了如何使用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的用例,谢谢。 - Andy Allison

4
根据.NET Core 2.0+仓库中的文档,需要在提供的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();
}

//...

1
谢谢,但我正在寻找一种从 DI 框架中获取正确 ILogger 实例的方法,而不是必须使用全局的 Log.Logger 实例。 - Mr. T
@Mr.T,我认为你没有理解扩展方法的作用。它实际上将ILogger包含在服务集合中,以便进行DI。这是它唯一的目的。它集成到DI框架的日志工厂中。他们只提到Log.Logger,因为它是底层提供程序,仍然需要首先配置才能正确运行所有内容。 - Nkosi
@Mr.T 举个例子,参考源代码。https://github.com/serilog/serilog-extensions-hosting/blob/dev/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs - Nkosi

0

.Net6 中有一些变化

这是我的 program.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();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接