首页 > 解决方案 > ELK 堆栈未将内部解构属性接收为已解构,但作为转义字符串

问题描述

我不确定这是否是 Serilog、ELK、Service Fabric、代码或配置问题。

我正在编写 Service Fabric 无状态服务。我的日志记录配置行是这样的:

            Logger = new LoggerConfiguration()
                .WriteTo.EventFlow(loggingOptions.DiagnosticPipeline)
                .Destructure.With<JsonNetDestructuringPolicy>()
                .Enrich.FromLogContext()
                .CreateLogger()
                .ForContext(properties);

...其中 properties 是 PropertyEnricher 数组,Policy 来自Destructurama 的 JsonNetDestructuringPolicy

我有一个成功解构的自定义对象基类,所以如果我称它为数据,那么在 ELK 的 JSON 选项卡中我看到:

"payload": {
  "Data": {
    "Property1": "Prop Value",
    "Property2": "Prop2 Value"
  }
}

但是,当其中一个内部对象也被解构时,它会作为转义的 JSON 字符串发送,而不是被解构,属性名称周围没有引号:

"payload": {
  "Data": {
    "Property1": "Prop Value",
    "DestructuredProp": "{InnerProperty: \"Inner Value\"}"
  }
}

我的预期是:

"payload": {
  "Data": {
    "Property1": "Prop Value",
    "DestructuredProp": {
      "InnerProperty": "Inner Value"
    }
  }
}

我不知道为什么没有给内部属性名称加上引号,或者为什么整个值被转义和引用而不是解构。我已经验证我的解构代码正在执行。例如,我可以手动在属性名称周围添加引号,但这只会导致内部值中出现更多转义引号。

我自己的代码直接从 C# 解构它。我认为这可能是我的解构代码中的一个错误,所以我环顾四周,发现了Destructurama 的 JsonNetDestructuringPolicy,所以我尝试了,用 JObject.fromObject() 转换我的对象,但同样的事情发生了。

我很确定我应该能够用 Serilog 做到这一点。如果它不能做超过一层的深度,我认为不会有深度限制设置。为什么这不起作用?我尝试在 Kibana 中刷新字段索引,但 JSON 视图显示了转义字符串,所以我很确定它发送不正确,并且不是 ELK 问题。

- -编辑 - -

这是我尝试过的解构策略。我的初始对象是 JsonEvent,它有一个没有解构的 Dictionary,即使成功调用了 Dictionayr 策略。

    public class JsonEventDestructuringPolicy : IDestructuringPolicy
    {
        public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
        {
            if (value is JsonEvent jsonEvent)
            {
                var properties = new List<LogEventProperty>();
                foreach (var property in value.GetType().GetProperties())
                {
                    var propertyValue = property.GetValue(value);
                    var isCollection = propertyValue is ICollection<Dictionary<string,string>>;
                    var isDictionary = propertyValue is Dictionary<string,string>;
                    if (isCollection)
                        LoggingContext.Message("Found collection of dictionary: " + property.Name);
                    else if (isDictionary)
                        LoggingContext.Message("Found dictionary: " + property.Name);
                    else if (property.Name.Equals("Parameters"))
                        LoggingContext.Message("Found Parameters: " + propertyValue.GetType());
                    if (propertyValue != null)
                        properties.Add(new LogEventProperty(property.Name, propertyValueFactory.CreatePropertyValue(propertyValue, isCollection || isDictionary)));
                }
                result = new StructureValue(properties);

                return true;
            }

            if (value is Dictionary<string, string> dictionary)
            {
                var properties = new List<LogEventProperty>();
                foreach (var kvp in dictionary)
                {
                    if (!string.IsNullOrWhiteSpace(kvp.Value))
                        properties.Add(new LogEventProperty("\"" + kvp.Key + "\"", propertyValueFactory.CreatePropertyValue(kvp.Value)));
                }
                result = new StructureValue(properties);

                return true;
            }

            result = null;
            return false;
        }
    }

它被这样调用:

        public static void Message(JsonEvent message)
        {
            Logger.ForContext(GetEnrichers(message))
                .Information(message.Event);
        }

        private static IEnumerable<ILogEventEnricher> GetEnrichers(JsonEvent message)
        {
            return new List<ILogEventEnricher>()
                .Add("Data", message, true)
                .Add("CorrelationId", ServiceTracingContext.CorrelationId)
                .Add("CorrelationDateTime", ServiceTracingContext.CorrelationDateTime)
                .Add("RouteTemplate", ServiceTracingContext.RouteTemplate)
                .ToArray();
        }

标签: azure-service-fabricelastic-stackserilogelk

解决方案


推荐阅读