Я не уверен, что это проблема 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();
}