Serilog 属性 丰富但仍然需要调用实际写入调用?

Serilog property enrichment but still required in call to actual write call?

我正在将 Serilog 添加到我们的日志记录基础设施中,但对以下内容感到困惑:

public class OzCpWriteEntryExInput : OzCpAppServiceInputBase
{
    private readonly ILogger _Logger;

    /// <summary>
    ///     Class constructor
    /// </summary>
    public OzCpWriteEntryExInput(ILogger aLogger)
    {
        //Save params supplied
        _Logger = aLogger;

        //Create resources required
        Entry = new OzCpLogEntryContextInput();
    }

    public OzCpLogEntryContextInput Entry { get; set; }

    public ILogger Logger => _Logger;
}

public class OzCpLoggingService : OzCruisingPlatformAppServiceBase, IOzCpLoggingService
{
    private const string MESSAGE_TEMPLATE =
        "{LogVersion} {DateTimeUtc:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{LevelRange}] [{ApplicationHostName}] [{ApplicationName}] [{ApplicationVersion}] [{Location}] {Message}{NewLine}{Exception}{NewLine}{StackTrace}{NewLine}{UserDataKind}{@UserData}";

    public OzCpBuildLoggerOutput BuildLogger(OzCpBuildLoggerInput aParams)
    {
        OzCpBuildLoggerOutput result = new OzCpBuildLoggerOutput();
        //#TODO (DE) Convert logger hard coded values into settings
        bool logToUdp = true;

        //By default logging will include all events
        LoggerConfiguration loggerConfiguration = new LoggerConfiguration()
            .Enrich.WithProperty("LogVersion", "01.00")
            .MinimumLevel.Verbose();

        if (logToUdp)
        {
            loggerConfiguration.WriteTo.Udp(IPAddress.Loopback, 11000, 0, LogEventLevel.Verbose, MESSAGE_TEMPLATE);
        }

        //Finally we can build the logger
        result.Logger = loggerConfiguration.CreateLogger();

        return result;
    }

    /// <summary>
    ///     Writes an entry to the supplied logger and associated log sinks.
    /// </summary>
    /// <param name="aParams">Parameters defining the entry to be written.</param>
    /// <returns>Returns whether the entry was written to the logger.</returns>
    public OzCpWriteEntryExOutput WriteEntryEx(OzCpWriteEntryExInput aParams)
    {
        OzCpWriteEntryExOutput result = new OzCpWriteEntryExOutput();

        //These variable values are only the ones out of the entry as the logger "enriches" the other values based on
        //what has been passed in when it was configured
        object[] messageTemplateVariableValues =
        {
            "***",   //Log Version is actually an enriched property!!!!
            aParams.Entry.DateTimeUtc,
            aParams.Entry.LevelRange,
            aParams.Entry.Location,
            aParams.Entry.StackTrace,
            aParams.Entry.UserDataKind,
            aParams.Entry.UserData
        };

        switch (aParams.Entry.EntryKind)
        {
            case OzCpLoggingEntryKindEnum.Verbose:
                aParams.Logger.Verbose(aParams.Entry.Exception, MESSAGE_TEMPLATE, messageTemplateVariableValues);
                break;
        }

        return result;
    }
}

WriteLogEx() 的调用者最终可以提供他们自己的 Serilog.ILogger。我不会深入探讨为什么会出现这种情况,只是假设这是一项要求。

作为示例,我包含了 BuildLogger(),它设置一个 ILogger 以使用自定义消息模板和一些 其他属性通过丰富配置构建器写入 UDP

一切都很简单。但是,现在当我使用 ILogger.Verbose() 写入 ILogger 时,我需要为消息模板中的标记传递参数。

然而这似乎是基于 序数 所以第一个进入 {LogVersion} 应该通过先前为记录器设置的丰富配置来完成。

如果我不使用 LogVersion,格式化的消息模板将被关闭一个,如果我包含它,那么我自然会得到:

*** 2016-04-14 14:53:57.677 +10:00 [Information]...

而不是我想要的是:

01.00 2016-04-14 14:53:57.677 +10:00 [Information]...

那么如何调用 ILogger 的日志记录方法并按名称而不是位置传递标记值?

不是在 .Verbose() 语句中传递这些,而是​​在那里传递特定于事件的数据。可以通过上下文化记录器来添加其他输出模板属性:

var ctx = logger.ForContext("DateTimeUtc", aParams.Entry.DateTimeUtc)
                .ForContext("LevelRange", aParams.Entry.LevelRange)
                // and so-on.

ctx.Verbose("Message here...");

有一个 ForContext() 重载接受一个 PropertyEnricher 数组,我相信你可以用它来整理东西。