Serilog не пишет информацию об ошибке в ElasticSearch

Настроил Serilog чтобы писать сообщения в Elastic, но столкнулся с проблемой.

Serilog пишет в Elastic только сообщение лога, но не информацию об ошибке, а переданное исключение игнорирует. Стоит отметить что информация об исключении корректно пишется в консоль, но не в Elastic.

Вот так пишутся логи с ошибками:

В случае такого логгирования параметр exception не будет отображен в логах Elastic, в логах будет отображено только сообщение An error occurred while processing HTTP request.

logger.LogError(exception, "An error occurred while processing HTTP request");

Вот так настраивается логирование:

/// <summary>
/// Provides extension methods for adding ElasticSearch logging services to an <see cref="IInfrastructureBuilder"/>.
/// </summary>
public static class ElasticSearchLoggerExtension
{
    /// <summary>
    /// Adds ElasticSearch logging services to the <see cref="IInfrastructureBuilder"/>.
    /// </summary>
    /// <param name="builder">The infrastructure builder to which the ElasticSearch logging services will be added.</param>
    /// <param name="configureOptions">A delegate that configures the ElasticSearch options.</param>
    /// <returns>The updated <see cref="IInfrastructureBuilder"/> with the added ElasticSearch logging services.</returns>
    /// <exception cref="InfrastructureConfigurationException">
    /// Thrown when the ElasticSearch configuration is invalid, such as an incorrect connection string.
    /// </exception>
    /// <remarks>
    /// This method configures logging services and registers the following components:
    /// <list type="bullet">
    ///     <item><description><see cref="ElasticSearchConfigureOptions"/> - Singleton service for storing ElasticSearch configuration.</description></item>
    ///     <item><description><see cref="Serilog.ILogger"/> - Global logger instance configured with Serilog, including ElasticSearch sink.</description></item>
    ///     <item><description><see cref="ILogger{TCategoryName}"/> - Logging services integrated with ASP.NET Core's logging infrastructure.</description></item>
    /// </list>
    /// Additionally, this method configures the following logging behaviors:
    /// <list type="bullet">
    ///     <item><description>Logs are enriched with context properties such as assembly name and environment.</description></item>
    ///     <item><description>Logs are written to both the console and ElasticSearch.</description></item>
    ///     <item><description>ElasticSearch index format is set to <c>logs-YYYY</c>, where <c>YYYY</c> is the current year.</description></item>
    /// </list>
    /// </remarks>
    public static IInfrastructureBuilder AddElasticSearchLogger(this IInfrastructureBuilder builder, Action<ElasticSearchConfigureOptions> configureOptions)
    {
        var options = new ElasticSearchConfigureOptions();
        configureOptions.Invoke(options);

        if (!options.IsEnable)
            return builder;

        options.EnsureSuccessValidation("Invalid ElasticSearch configuration. Please check connection");

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Is(options.EventLevel)
            .Enrich.WithCorrelationId()
            .Enrich.WithExceptionDetails()
            .Enrich.WithProperty("Assembly", Assembly.GetExecutingAssembly().GetName().Name)
            .Enrich.WithProperty(InfrastructureImmutable.ASPNETCore.EnvProperty, Environment.GetEnvironmentVariable(InfrastructureImmutable.ASPNETCore.AspNetCoreEnv)!)
            .ReadFrom.Configuration(options.Configuration)
            .WriteTo.Console(new CompactJsonFormatter())
            .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(options.Connection))
            {
                BatchPostingLimit = 50,
                Period = TimeSpan.FromSeconds(2),
                BufferFileSizeLimitBytes = 1024 * 1024,
                BufferRetainedInvalidPayloadsLimitBytes = 5000,
                AutoRegisterTemplate = true,
                OverwriteTemplate = true,
                CustomFormatter = new ExceptionAsObjectJsonFormatter(renderMessage: true, formatStackTraceAsArray: true),
                IndexFormat = options.Index,
                TypeName = null
            })
            .CreateLogger();

        builder.Services.AddLogging(logger =>
        {
            logger.AddSerilog(Log.Logger);
            logger.AddConsole();
        });

        return builder;
    }
}

Опции для настройки логгера:

/// <summary>
/// Provides configuration options for Elasticsearch connection and index settings.
/// This class validates the essential configuration required to connect to Elasticsearch.
/// </summary>
/// <remarks>
/// The class inherits from <see cref="Validator"/> to provide validation capabilities
/// for Elasticsearch configuration parameters.
/// </remarks>
public sealed class ElasticSearchConfigureOptions : Validator
{
    /// <summary>
    /// Gets or sets the connection string for Elasticsearch cluster.
    /// </summary>
    /// <value>
    /// The connection string in URI format (e.g., "http://localhost:9200").
    /// This property must be set to a non-null, non-empty value.
    /// </value>
    public string Connection { internal get; set; } = null!;

    /// <summary>
    /// Gets or sets the index name pattern for Elasticsearch.
    /// </summary>
    /// <value>
    /// The index name with a default pattern of "logs-YYYY" where YYYY is the current UTC year.
    /// Custom index names can be set but must start with "logs" (case insensitive).
    /// </value>
    public string Index { internal get; set; } = $"logs-{DateTime.UtcNow:yyyy.MM.dd}";

    /// <summary>
    /// Gets or sets the minimum log level for Elasticsearch.
    /// </summary>
    /// <value>
    /// The minimum log event level. Defaults to <see cref="LogEventLevel.Information"/>.
    /// </value>
    public LogEventLevel EventLevel { internal get; set; } = LogEventLevel.Information;

    /// <summary>
    /// Gets or sets the configuration settings for Elasticsearch.
    /// </summary>
    /// <value>
    /// The <see cref="IConfiguration"/> instance containing additional Elasticsearch settings.
    /// This property must be set to a non-null value.
    /// </value>
    public IConfiguration Configuration { internal get; set; } = null!;

    /// <summary>
    /// Validates whether the Elasticsearch configuration is properly set.
    /// </summary>
    /// <returns>
    /// <c>true</c> if the configuration is valid; otherwise, <c>false</c>.
    /// </returns>
    /// <remarks>
    /// The configuration is considered valid when:
    /// <list type="bullet">
    ///   <item><description>The <see cref="Connection"/> property is not null, empty, or whitespace</description></item>
    ///   <item><description>The <see cref="Configuration"/> property is not null</description></item>
    ///   <item><description>The <see cref="Index"/> property does not start with "logs" (case insensitive)</description></item>
    /// </list>
    /// </remarks>
    public override bool IsValidConfigure()
    {
        if (string.IsNullOrWhiteSpace(Connection) || Configuration is null || !Index.StartsWith("logs", StringComparison.OrdinalIgnoreCase))
            return false;

        return true;
    }
}

Ответы (0 шт):