如何将完整的对象添加到消息中未写出的 Serilog Azure Tablestorage 接收器?

How can I add a complete object to Serilog Azure Tablestorage sink, which is not written out in the message?

所以,我现在正在尝试将 Serilog 包含在我的应用程序中,并且想知道以下内容:

是否可以添加一个对象,以便我的 Azure Tablestorage 接收器将其拾取并将其完全写入相应 "Data" 列中的 JSON,而不将其添加到纯文本消息中?

我最初的方法是这样的:

m_logger.Information("{message} @{context}", message, context);

这就是我的问题的来源。这行得通,但我想让消息本身保持人类可读性,并将上下文中的元数据保存在单独的列中。

所以,我的第二次尝试现在看起来像这样:

using (LogContext.PushProperty("context", context))
{
    m_logger.Information("{message}", message);
}

鉴于此,我将其添加到我的记录器配置中:.Enrich.FromLogContext()

现在这种工作,对象不再出现在消息中,实际上被添加到数据中,但不是完全写出到 JSON,这就是我最终得到的我在 Tablestorage 端点上的数据列:

{"Timestamp":"2019-09-01T08:52:29.4835746+02:00","Level":"Information","MessageTemplate":"{message}","Properties":{"message":"Login happened","context":"MooMed.Core.DataTypes.Session.Context"}}

所以,这似乎在内部只是调用 .ToString()

我现在想知道是否有一种内置方法可以递归地对对象进行 jsonify,或者我是否必须(表面上)只覆盖 Context [=36 中的 .ToString() =]?

除非您明确告诉 Serilog 解构您的上下文数据,否则它只会使用 ToString 表示。在您最初的方法中,您告诉 Serilog 通过使用 @ 符号进行解构(尽管我假设您在花括号内而不是在外面使用它,即 {@context} 而不是 @{context} 否则这不应该工作)。

当使用 LogContext 时,你可以告诉 Serilog 通过在使用 属性:

时传递一个标志来解构对象
using (LogContext.PushProperty("context", context, destructureObjects: true))
{
    // ...
}

我假设您知道这会将上下文添加到 using 块内记录的所有消息,包括调用堆栈下方发生的任何消息。作为替代方案,如果您想更好地控制将上下文添加到哪些消息,您还可以创建一个使用此上下文数据丰富的临时记录器。这是使用 ILogger.ForContext 方法完成的:

var enrichedLogger = m_logger.ForContext("context", context, destructureObjects: true);

// Use `enrichedLogger` instead of `m_logger` whenever you want context data included.
enrichedLogger.Information("This message has context data attached!");
m_logger.Information("This message does not have context data attached.");

您也可以使用与上述相同的方法为单个消息添加上下文:

m_logger.ForContext("context", context, destructureObjects: true)
    .Information("This message has context data attached!")