问题描述
我有很多这样的日志:
<div class="quotes-wrapper">
<div class="quotes-wrapper__quote quotes-first">
<p>Lorem ipsum dolor sit amet,consectetur adipiscing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris quis nostrud nisi ut aliquip ex ea commodo consequat.</p>
<p>Jhone Due,Photographer</p>
</div>
<div class="quotes-wrapper__quote">
<p>haha text</p>
<p>Abraham Due,Photographer</p>
</div>
<div class="quotes-wrapper__quote">
<p>another text</p>
<p>David Due,Photographer</p>
</div>
<div class="quotes-wrapper__quote">
<p>Lorem ipsum dolor sit amet,quis nostrud exercitation ullamco laboris quis nostrud nisi ut aliquip ex ea commodo consequat.</p>
<p>Lora Due,Photographer</p>
</div>
</div>
此日志通过RabbitMq-> LogStash-> Elastic并最终生成许多字段(我假设每个属性一个字段)。最终,我在Elastic中有成千上万个字段,带来了各种各样的问题。
如果我将整个对象指定为参数,通常意味着我不太关心要解析其所有字段,如果将其存储为单个字符串对象(但仍然以json)。有没有办法在Serilog中自定义它?
解决方法
我认为您可以使用$
运算符强制进行字符串化。而且我认为您可以覆盖ToString
方法来调整输出。 documentation中还有一个简短的示例如何强制字符串化:
var unknown = new[] { 1,2,3 }
Log.Information("Received {$Data}",unknown);
这是日志记录功能的输出:
Received "System.Int32[]"
,
如果您很高兴更改对象的ToString()
表示形式,则 @flaxel's answer会很好用。如果您已经覆盖了ToString()
,或者不想让它返回JSON字符串,请考虑以下选项之一。
如果您不想一次将类型记录为JSON 全部,请考虑在记录消息时仅序列化对象。这是最明确的方法,它使您可以选择哪些消息具有序列化形式,哪些消息具有重组形式,但这可能会使您的日志语句变得很冗长:
// Using Newtonsoft.Json to serialize.
Log.Information("Submitting order {Order}",JsonConvert.SerializeObject(order));
如果您总是要将类型序列化为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);
此方法的另一个优点是,如果您要更改表示该类型对象的方式,或者要恢复为默认的分解方法,则只需更改配置记录器时使用的策略(即上面代码段中的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>()
// ...