Feiyu Zhou
Feiyu Zhou

Reputation: 4544

How to write the right appsettings.json file for custom Enricher within argument

I have a custom Enricher: CorrelationIdsEnricher in order to write the CorrelationId and RequestId to log, and its constructor has an argument: ICorrelationContextProvider for passing the correlation context provider.

In my project, i config the serilog by reading the appsettings.json config file. And here's the config file:

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Common.Logging", "Common.Correlation" ],
    "MinimumLevel": "Debug",
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{SourceContext}] [{EventId}] [{RequestId} {CorrelationId}] {Message}{NewLine}{Exception}",
          "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      {
        "Name": "WithCorrelationIds",
        "Args": {
          "provider": "Correlation.ServerContextProvider::Default, Common.Correlation"
        }
      }
    ],
  }
}

However it can not set the CorrelationIdsEnricher correctly.

Does anyone know why?

Upvotes: 2

Views: 3169

Answers (1)

Feiyu Zhou
Feiyu Zhou

Reputation: 4544

The reason is that i forgot to add the WithCorrelationIds extension method. I thought implementing the CorrelationIdsEnricher is enough at first.

After looking into the source code ConfigurationReader.cs of serilog-settings-configuration, i found that i forget to implement extensions WithCorrelationIds.

That's to say, in order to support initializing serilog from configuration for our custom Enricher and Sink, we need to not only create the Enricher and Sink class but also implement their LoggerSinkConfiguration extensions.

Attached the CorrelationIdsEnricher implementation:

using Common.Correlation;
using Serilog.Core;
using Serilog.Events;

namespace Common.Logging.Enrichers
{
    public class CorrelationIdsEnricher : ILogEventEnricher
    {
        private readonly ICorrelationContextProvider _provider;

        public CorrelationIdsEnricher(ICorrelationContextProvider provider)
        {
            _provider = provider;
        }

        public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
        {
            var (requestId, correlationId) = GetIds();
            logEvent.AddPropertyIfAbsent(
                propertyFactory.CreateProperty("RequestId", requestId, false));
            logEvent.AddPropertyIfAbsent(
                propertyFactory.CreateProperty("CorrelationId", correlationId, false));
        }

        private (string requestId, string correlationId) GetIds()
        {
            var ctx = _provider.Context;
            return (ctx?.RequestId ?? string.Empty, ctx?.CorrelationId ?? string.Empty);
        }
    }
}

And LoggerEnrichmentConfiguration Extensions:

public static LoggerConfiguration WithCorrelationIds(
    this LoggerEnrichmentConfiguration enrichmentConfiguration,
    ICorrelationContextProvider provider)
{
    return enrichmentConfiguration.With(new CorrelationIdsEnricher(provider));
}

And here's a mocked correlation provider:

public class CorrelationContextProvider : ICorrelationContextProvider
{
    public static ICorrelationContextProvider Default { get; } = new CorrelationContextProvider();
    public ICorrelationContext Context => new CorrelationContext();
}

Upvotes: 5

Related Questions