如何在 Serilog 中将对象序列化为字符串?

Sib*_*Guy 3 serilog

我有很多这样的日志:

Log.Information("Submitting order {@order}", order);
Run Code Online (Sandbox Code Playgroud)

该日志经过 RabbitMq -> LogStash -> Elastic,最终生成许多字段(我假设每个属性对应一个字段)。最终我在 Elastic 中拥有了成千上万的字段,这带来了各种各样的问题。

如果我将整个对象指定为参数,通常意味着我不太关心解析其所有字段,如果将其存储为单个字符串对象(但仍序列化为 json),我会非常高兴。有没有办法在 Serilog 中自定义它?

rob*_*ker 6

如果您乐意更改ToString()对象的表示,@flaxel 的答案效果很好。如果您已经覆盖ToString()或者不希望它返回 JSON 字符串,请考虑以下选项之一。


如果您不想始终将类型记录为 JSON ,请考虑在记录消息时仅序列化对象。这是最明确的方法,允许您选择哪些消息具有序列化形式,哪些消息具有解构形式,但它可能会使您的日志语句非常冗长:

// Using Newtonsoft.Json to serialize.
Log.Information("Submitting order {Order}", JsonConvert.SerializeObject(order));
Run Code Online (Sandbox Code Playgroud)

如果您始终希望将类型序列化为 JSON,则可以为该特定类型注册解构策略。这可以使您的日志语句简洁并确保类型始终以相同的方式序列化:

// When configuring your logger.
Log.Logger = new LoggerConfiguration()
    .Destructure.ByTransforming<Order>(order => JsonConvert.SerializeObject(order))
    // ...

// This will use the destructurer registered above, so will convert to a JSON string.
Log.Information("Submitting order {@Order}", order);

// These will still use the ToString() method.
Log.Information("Submitting order {Order}", order);
Log.Information("Submitting order {$Order}", order);
Run Code Online (Sandbox Code Playgroud)

这种方法的另一个优点是,如果您想要更改表示该类型对象的方式,或者想要恢复到默认的解构方法,则只需更改配置记录器时使用的策略(即上面代码片段中的 lambda)。

如果您的序列化方法太复杂而无法适应 lambda,或者您想对大量类型使用相同的序列化方法,您可以定义自己的序列化方法,IDestructuringPolicy然后以类似的方式注册它:

class SerializationPolicy : IDestructuringPolicy
{
    public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
    {
        // Check type of `value` and serialize if required.
    }
}

// When configuring your logger.
Log.Logger = new LoggerConfiguration()
    .Destructure.With<SerializationPolicy>()
    // ...
Run Code Online (Sandbox Code Playgroud)