【问题标题】:How to format serilog property names?如何格式化 serilog 属性名称?
【发布时间】:2019-06-16 15:37:22
【问题描述】:

我正在使用SerilogSerilog.Formatting.Compact 将日志写入文件。如何动态格式化属性名称?

我希望每个属性名称都包含其类型。

例如:bool_property_name、string_property_name、date_property_name....

logger.Information("this is a message with {property_name}", "value");

logger
    .ForContext("property_name", "value")
    .Information("this is a message");

应该在日志中:

{ ...., string_property_name: "value" }

【问题讨论】:

  • 没有开箱即用的这种机制(去阅读源代码)。但问题是:为什么?!
  • 弹性搜索映射的问题。当我有几个同名的属性时
  • 啊,我想看看 repo 的问题是否出现是值得的 - 也许值得在 gitter.im/serilog 询问其他人做了什么
  • 你为什么不自己在 logger.Information 行中添加它? IE。只需写: logger.Information("这是一条带有 {string_property_name} 的消息", "value");也许你在一个非常通用的地方有这个日志行,但否则你在手动输入日志行时总是知道你有什么属性。
  • 我也可以重命名该属性,但我担心它可能会再次发生在另一个开发者身上

标签: c# asp.net serilog


【解决方案1】:

这就是我找到的解决方案。

关于此解决方案需要注意的一些要点:

  • 它不格式化消息模板。
  • 它格式化每个属性 - 例如,包括由第三方扩充器添加的属性。
  • 它仍然没有生产。如果发现任何错误,我会更新。
public class LogEventPropertiesNameFormatter
{
    public void Format(LogEvent logEvent)
    {
        var keys = new List<string>(logEvent.Properties.Keys);

        foreach (var key in keys)
        {
            logEvent.AddPropertyIfAbsent(Visit(key, logEvent.Properties[key]));
            logEvent.RemovePropertyIfPresent(key);
        }
    }

    private LogEventProperty Visit(string name, LogEventPropertyValue value)
    {
        switch (value)
        {
        case null:
            throw new ArgumentNullException(nameof(value));
        case ScalarValue scalar:
            return VisitScalar(name, scalar);
        case SequenceValue sequence:
            return VisitSequence(name, sequence);
        case StructureValue scalar:
            return VisitStructure(name, scalar);
        case DictionaryValue dictionary:
            return VisitDictionary(name, dictionary);
        default:
            return new LogEventProperty(name, value);
    }

    private LogEventProperty VisitDictionary(string name, DictionaryValue dictionary)
    {
        var formattedElements = new Dictionary<ScalarValue, LogEventPropertyValue>(dictionary.Elements.Count);

        foreach (var element in dictionary.Elements)
        {
            var property = Visit(element.Key.Value.ToString(), element.Value);
            formattedElements.Add(new ScalarValue(property.Name), property.Value);
        }

        return LogEventProperty($"dict_{name}", new DictionaryValue(formattedElements));
    }

    private LogEventProperty VisitStructure(string name, StructureValue structure)
    {
        var properties = structure.Properties.Select(p => Visit(p.Name, p.Value));
        return new LogEventProperty($"struct_{name}", new StructureValue(properties));
    }

    private LogEventProperty VisitSequence(string name, SequenceValue sequence)
    {
        var elements = sequence.Elements.Select(e => Visit(null, e).Value);
        return new LogEventProperty($"seq_{name}", new SequenceValue(elements));
    }

    private LogEventProperty VisitScalar(string name, ScalarValue scalar)
    {
        return new LogEventProperty($"{GetScalarValueType(scalar)}_{name}", scalar);
    }

    private string GetScalarValueType(ScalarValue value)
    {
        switch (value.Value)
        {
            case null:
                return "null";
            case string _:
            case TimeSpan _:
                return "s";
            case int _:
            case uint _:
            case long _:
            case ulong _:
            case decimal _:
            case byte _:
            case sbyte _:
            case short _:
            case ushort _:
            case double _:
            case float _:
                return "n";
            case bool _:
                return "b";
            case DateTime _:
            case DateTimeOffset _:
                return "d";
            default:
                return "o";
        }
    }
}

public class CompactJsonFormatterTypeOverride : ITextFormatter
{
    private readonly ITextFormatter _textFormatter;
    private readonly LogEventPropertiesNameFormatter _logEventPropertiesNameFormatter;

    public CompactJsonFormatterTypeOverride()
    {
        _textFormatter = new CompactJsonFormatter();
        _logEventPropertiesNameFormatter = new LogEventPropertiesNameFormatter();
    }

    public void Format(LogEvent logEvent, TextWriter output)
    {
        _logEventPropertiesNameFormatter.Format(logEvent);
        _textFormatter.Format(logEvent, output);
    }
}

然后在记录器配置中:

new LoggerConfiguration().
    WriteTo.File(new CompactJsonFormatterTypeOverride(), "log.log")
    .CreateLogger();

【讨论】:

    【解决方案2】:
    logger.Information($"this is a message with {property_name}");
    

    您可以在消息中记录您的请求,只需将 $ 放在 start { } 大括号中作为属性。

    【讨论】:

    • 但是我根本就没有房产
    • 好的,你有没有使用那里的properites?
    • 是的。我在 elasticsearch 中查询它们
    • 他们是谁?
    • 很抱歉,我不太明白您的要求和目的。我有诸如请求、ID 等属性...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    相关资源
    最近更新 更多