【问题标题】:Why must I manually dispose the Serilog Logger (Sumologic sink) when the dispose option is true?当 dispose 选项为 true 时,为什么我必须手动处置 Serilog Logger(Sumologic sink)?
【发布时间】:2021-05-14 11:23:53
【问题描述】:

我已经使用配置了 Serilog(我已经尝试使用 dispose 选项 true 和 false)

services.AddLogging(
    loggingBuilder =>
    {
        //Create Serilog logger from AppSettings.json properties.
        _logger = new LoggerConfiguration()
            .ReadFrom.Configuration(configuration)
            .CreateLogger();
        loggingBuilder.AddSerilog(_logger, true);
    });

应用设置配置

    "Logging": {
        "IncludeScopes": true,
        "LogLevel": {
            "Default": "Debug",
            "System": "Warning",
            "Microsoft": "Warning"
        },
        "Debug": {
            "LogLevel": {
                "Default": "Debug"
            }
        },
        "Console": {
            "LogLevel": {
                "Default": "Information"
            }
        }
    },
    "Serilog": {
        "Using": [
            "Serilog.Sinks.Console",
            "Serilog.Sinks.SumoLogic",
            "Serilog.Formatting.Compact"
        ],
        "MinimumLevel": {
            "Default": "Information",
            "Override": {
                "System": "Warning",
                "Microsoft": "Warning"
            }
        },
        "Filter": [
            {
                "Name": "ByExcluding",
                "Args": {
                    "expression": "RequestPath = '/api/health'"
                }
            },
            {
                "Name": "ByExcluding",
                "Args": {
                    "expression": "RequestPath = '/api/info'"
                }
            }
        ],
        "WriteTo": [
            {
                "Name": "SumoLogic",
                "Args": {
                    "endpointUrl": "todo-setSumoLogEndpointUrl",
                    "sourceName": "sourceName",
                    "sourceCategory": "sourceCategory",
                    "textFormatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
                }
            },
            {
                "Name": "Console",
                "Args": {
                    "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
                    "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext} {Message:lj}{NewLine}{Exception}",
                    "restrictedToMinimumLevel": "Debug"
                }
            }
        ],
        "Enrich": [
            "FromLogContext",
            "WithMachineName",
            "WithThreadId"
        ],

我正在使用 Sumologic 水槽 https://www.nuget.org/packages/Serilog.Sinks.SumoLogic/

我已将我的DbContext 配置为也使用 Serilog

private void ConfigureDbContext(IServiceCollection services)
{
    ServiceProvider? provider = services.BuildServiceProvider();
    ILoggerFactory? loggerFactory = provider.GetService<ILoggerFactory>();
    services.AddDbContext<ApiDbContext>(options =>
    {
        string? connectionString = Configuration.GetConnectionString("ApiDatabase");
        // NodaTime allows the use of zoned times.
        options
            .UseNpgsql(connectionString, npgsqlOptions => npgsqlOptions.UseNodaTime())
            // Using snake case avoids the need for quoting tables and columns.
            .UseSnakeCaseNamingConvention();
        if (loggerFactory != null)
        {
            options.UseSerilog(loggerFactory);
        }
        if (!IsDevelopment)
        {
            return;
        }
        options.EnableSensitiveDataLogging()
            .EnableDetailedErrors()
            .LogTo(Console.WriteLine);
    });
}

在运行数据库迁移时,我遇到了导致应用程序启动失败的致命异常,如下所示:

Npgsql.PostgresException (0x80004005): 23505: duplicate key value violates unique constraint \"pk_pdt_users\"
   at Npgsql.NpgsqlConnector.<ReadMessage>g__ReadMessageLong|194_0(NpgsqlConnector connector, Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
   at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
   at Npgsql.NpgsqlDataReader.NextResult()
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteNonQuery(Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade)
   at Precisely.Pdx.Api.Web.Startup.UpdateDatabase(IApplicationBuilder app) in /Users/richardcollette/Documents/code/sdm/pdx_api/Precisely.Pdx.Api/Precisely.Pdx.Api.Web/Startup.cs:line 190
   at Precisely.Pdx.Api.Web.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider apiVersionDescriptionProvider, ILogger`1 log) in /Users/richardcollette/Documents/code/sdm/pdx_api/Precisely.Pdx.Api/Precisely.Pdx.Api.Web/Startup.cs:line 121

如果我什么都不做,EF 记录的错误(包含失败的 SQL 语句)不会被记录,也不会记录由此产生的异常。

相反,我必须将 Serilog Logger 保留为私有字段,捕获异常,记录它,然后手动处理 Logger。

try
{
    UpdateDatabase(app);
}
catch (Exception ex)
{
    log.LogError(ex, "Error applying migrations.");
    // This is a fatal error so we dispose the logger to ensure that it's messages are written.
    _logger?.Dispose();
    throw;
}

执行此操作后,将记录异常以及 sql 错误。

为什么 Serilog 和/或 sink 不自己写日志。提供程序是否未在致命错误场景中处理?

【问题讨论】:

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


    【解决方案1】:

    您有责任在应用程序结束之前刷新日志。见Lifecycle of Loggers

    您可以通过调用 Log.CloseAndFlush() 或处置您的记录器来做到这一点。

    public static int Main(string[] args)
    {
        ConfigureLogging(); // set up Serilog
    
        try
        {
            Log.Logger.Information("Custom.API Server is starting.");
            var webHost = BuildWebHost(args);
            webHost.Run();
    
            Log.Logger.Information("Custom.API Server is starting.");
            return 0;
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly.");
            return 1;
        }
        finally
        {
            Log.CloseAndFlush(); // <##<##<##<##<##<##
        }
    }
    

    【讨论】:

    • 我试过了,但没有用。我没有使用静态日志。我正在使用 ASP.NET 和 DI 来设置日志提供程序。我知道在关机时 DI 系统会在 IDisposables 上调用 Dispose。我只是不确定当 ASP.NET 启动的配置阶段遇到致命异常时会发生什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-07
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 2018-08-28
    相关资源
    最近更新 更多