如何使用 Serilog outputTemplate(固定宽度和截断 SourceContext)获得格式良好的文件日志

How to get nicely formatted file logs with Serilog outputTemplate (fixed width and truncation of SourceContext)

我正在从 log4net 切换到 Serilog,但错过了我在 log4net 中的一些格式化可能性。我没有找到关于我可以在 outputTemplate 中使用哪些格式化程序的任何文档。有什么方法可以完成我在下面描述的内容吗?

使用输出模板

"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u3}] ({SourceContext}) {Message:lj}{NewLine}{Exception}"

看起来像这样

[2020-03-30 11:31:06.464 DBG] (DomainLogic.TCMessageHandler) >>>Poll
[2020-03-30 11:31:06.481 DBG] (AmqpReader.Reader)    >>>Read
[2020-03-30 11:31:06.485 INF] (AmqpReader.Reader)       Fetched a message from the queue.
[2020-03-30 11:31:06.487 DBG] (AmqpReader.Reader)    <<<Read - 00:00:00.0066941
[2020-03-30 11:31:06.504 DBG] (DomainLogic.TCMessageHandler) <<<Poll - 00:00:00.0399191

这就是我想要的

[2020-03-30 11:31:06.464 DBG] (DomainLogic.TCMessageHandler) >>>Poll
[2020-03-30 11:31:06.481 DBG] (AmqpReader.Reader           )    >>>Read
[2020-03-30 11:31:06.485 INF] (AmqpReader.Reader           )       Fetched a message from the queue.
[2020-03-30 11:31:06.487 DBG] (AmqpReader.Reader           )    <<<Read - 00:00:00.0066941
[2020-03-30 11:31:06.504 DBG] (DomainLogic.TCMessageHandler) <<<Poll - 00:00:00.0399191

如果我设置了一个固定的宽度并且 SourceContext 比那个长,我希望它从左边截断。像这样

[2020-03-30 11:31:06.464 DBG] (ogic.TCMessageHandler) >>>Poll
[2020-03-30 11:31:06.481 DBG] (AmqpReader.Reader    )    >>>Read
[2020-03-30 11:31:06.485 INF] (AmqpReader.Reader    )       Fetched a message from the queue.
[2020-03-30 11:31:06.487 DBG] (AmqpReader.Reader    )    <<<Read - 00:00:00.0066941
[2020-03-30 11:31:06.504 DBG] (ogic.TCMessageHandler) <<<Poll - 00:00:00.0399191

Serilog 输出模板(和消息模板)基于 .NET 格式字符串,不支持截断替换值。没有办法直接在输出模板中执行此操作,尽管您可以编写一个 ILogEventEnricher 来替换 属性 的截断版本,具体取决于您打算如何使用事件。

这是一个完全符合我要求的浓缩器。

public class StaticWidthSourceContextEnricher : ILogEventEnricher
{
    private readonly int _width;

    public StaticWidthSourceContextEnricher(int width)
    {
        _width = width;
    }

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        var typeName = logEvent.Properties.GetValueOrDefault("SourceContext").ToString();

        if (typeName.Length > _width)
        {
            typeName = typeName.Substring(typeName.Length - _width);
        }
        else if (typeName.Length < _width)
        {
            typeName = typeName + new string(' ', _width - typeName.Length);
        }

        logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("SourceContext", typeName));
    }
}