【问题标题】:Utilize Message Template for Message Property Using Serilog使用 Serilog 将消息模板用于消息属性
【发布时间】:2018-10-29 00:19:31
【问题描述】:

我已采用 Serilog 来满足我的日志记录需求。 我(尽我所能)遵循 SOLID 原则,因此采用了Steven's adapter,这是一个很好的实现。

在大多数情况下,这很棒。我有一个名为 LogEntryDetail 的类,其中包含某些属性:

class LogEntryDetail
{
    public string Message {get;set;}
    public string MessageTemplate {get;set;}
    public string Properties {get;set;}

    // etc. etc.
}

我将像这样记录 LogEntryDetail:

    public void Log(LogEntryDetail logEntryDetail)
    {
        if (ReferenceEquals(null, logEntryDetail.Layer))
        {
            logEntryDetail.Layer = typeof(T).Name;
        }

        _logger.Write(ToLevel(logEntryDetail.Severity), logEntryDetail.Exception, logEntryDetail.MessageTemplate, logEntryDetail);
    }

我正在使用 MSSqlServer 接收器 (Serilog.Sinks.MSSqlServer) 进行错误记录,一切都很好。

我有一个性能记录器,我将它插入到我的请求管道中。对于这个记录器,我不想将每个属性都保存在 LogEntry 对象中。我只想将 Message 属性保存在我创建的表的 Message 列中。

因此,通常,当您在 serilog 记录器上调用 write 并传入一个复杂对象时,Message 列包含整个对象,序列化为 JSON。

我想知道是否可以通过某种方式将 MessageTemplate 指定为 {Message}{@Message} 之类的东西,以便数据库中的消息列仅包含存储在LogEntryDetail 对象的Message 属性中的字符串。任何其他属性都是多余的,浪费存储空间。

当我将MessageTemplate 指定为{Message} 时,Message 属性包含LogEntryDetail 类型的全名(包括命名空间)。

我觉得我很接近,只是在理解 Serilog 的 MessageTemplate 功能时遗漏了一些小东西。

【问题讨论】:

  • 链接答案中的简单内容没有解决结构化数据如何通过日志管道传递,也没有考虑像github.com/Suchiman/SerilogAnalyzer 中的静态分析。 Serilog 还有很多其他功能 - 您可能会在 nblumhardt.com/2016/06/… 中找到一些价值,以便更广泛地了解 API 的工作原理 :-) - HTH!
  • @NicholasBlumhardt 你是对的。但我在我的帖子中展示了它是如何在 Log 方法中传递的,该方法使用 API 的不同部分,即 _logger.write 和接受 MessageTemplate 的重载。我总是可以通过创建一个单独的记录器来解决这个问题,该记录器实现了一个用于性能记录的单独接口(无论如何它只用于 Dev 和 Staging)。正如 Steven 所建议的那样,我只是想看看我是否可以通过一个 Log 方法来汇集所有内容。干杯。

标签: serilog


【解决方案1】:

我将解释一下我在这里做了什么来尝试两全其美。在这里,我们似乎遇到了一个古老的开发者难题,即牺牲库的特定功能以符合 SOLID 原则。我们之前已经通过存储库抽象之类的东西看到了这一点,这使得无法利用它们抽象的一些 ORM 的粒度特性。

所以,我的 SerilogAdapter 看起来像这样:

public class SerilogLogAdapter<T> : ILogger
{
    private readonly Serilog.ILogger _logger;

    public SerilogLogAdapter(Serilog.ILogger logger)
    {
        _logger = logger;
    }

    public void Log(LogEntryDetail logEntryDetail)
    {
        if (ReferenceEquals(null, logEntryDetail.Layer))
        {
            logEntryDetail.Layer = typeof(T).Name;
        }

        if (logEntryDetail.MessageTemplate.Equals(MessageTemplates.LogEntryDetailMessageTemplate, StringComparison.Ordinal))
        {
            _logger.Write(ToLevel(logEntryDetail.Severity), logEntryDetail.Exception, logEntryDetail.MessageTemplate, logEntryDetail);
        }
        else
        {
            _logger.Write(ToLevel(logEntryDetail.Severity), logEntryDetail.MessageTemplate, logEntryDetail.Message, logEntryDetail.AdditionalInfo);
        }
    }

    private static LogEventLevel ToLevel(LoggingEventType severity) =>
        severity == LoggingEventType.Debug ? LogEventLevel.Debug :
            severity == LoggingEventType.Information ? LogEventLevel.Information :
                severity == LoggingEventType.Warning ? LogEventLevel.Warning :
                    severity == LoggingEventType.Error ? LogEventLevel.Error :
                        LogEventLevel.Fatal;
}

如果 MessageTemplate 是一个代表整个对象的模板,那么它将被记录下来。否则,可以使用自定义 MessageTemplate 并记录 Message 属性以及 AdditionalInfo 属性(字典)。

我们至少从 Serilog 中又挤出了一件东西,这也是它的强项之一——能够使用不同的消息模板进行日志记录,并通过消息模板搜索日志。

一定要让我知道它是否会更好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-28
    • 1970-01-01
    相关资源
    最近更新 更多