Внутреннее деструктурированное свойство не получено стеком ELK как деструктурированное, но как экранированная строка - PullRequest
1 голос
/ 25 января 2020

Я не уверен, что это проблема Serilog, ELK, Service Fabri c, кода или конфигурации.

Я пишу Service Fabri c Service без сохранения состояния. Моя строка конфигурации журналирования выглядит так:

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

... где properties - это массив PropertyEnricher, а политика - из JsonNetDestructuringPolicy * Destructurama .

У меня есть пользовательский базовый класс объекта, который успешно деструктурируется, поэтому, если я назову его Data, то на вкладке JSON в ELK я вижу:

"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#. Я подумал, что это могло быть ошибкой в ​​моем коде деструктуризации, поэтому я огляделся еще немного и обнаружил JsonNetDestructuringPolicy Destructurama, поэтому я попытался это, конвертируя мой объект с помощью JObject.fromObject (), но происходит то же самое с этим.

Я почти уверен, что смогу сделать это с Serilog. Я не думаю, что была бы установка предела глубины, если бы она не могла сделать более одного слоя глубиной. Почему это не работает? Я попытался обновить индекс поля в Kibana, но в представлении JSON отображается экранированная строка, поэтому я почти уверен, что она отправляется неправильно и не является проблемой ELK.

--- РЕДАКТИРОВАТЬ ---

Вот политика уничтожения, которую я пытался. Мой начальный объект - JsonEvent, и в нем есть Словарь, который не разрушается, даже если политика 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();
        }
...