Azure service fabric ELK堆栈未将内部destructured属性作为destructured接收,而是作为转义字符串接收
我不确定这是否是Serilog、ELK、服务结构、代码或配置问题 我正在编写一个服务结构无状态服务。我的日志配置行如下所示:Azure service fabric ELK堆栈未将内部destructured属性作为destructured接收,而是作为转义字符串接收,azure-service-fabric,elastic-stack,serilog,elk,Azure Service Fabric,Elastic Stack,Serilog,Elk,我不确定这是否是Serilog、ELK、服务结构、代码或配置问题 我正在编写一个服务结构无状态服务。我的日志配置行如下所示: Logger = new LoggerConfiguration() .WriteTo.EventFlow(loggingOptions.DiagnosticPipeline) .Destructure.With<JsonNetDestructuringPolicy>()
Logger = new LoggerConfiguration()
.WriteTo.EventFlow(loggingOptions.DiagnosticPipeline)
.Destructure.With<JsonNetDestructuringPolicy>()
.Enrich.FromLogContext()
.CreateLogger()
.ForContext(properties);
但是,当其中一个内部对象也被解构时,它将作为转义JSON字符串发送,而不是被解构,属性名称周围没有引号:
"payload": {
"Data": {
"Property1": "Prop Value",
"DestructuredProp": "{InnerProperty: \"Inner Value\"}"
}
}
我所期望的是:
"payload": {
"Data": {
"Property1": "Prop Value",
"DestructuredProp": {
"InnerProperty": "Inner Value"
}
}
}
我不知道为什么内部属性名不加引号,或者为什么整个值被转义和引用,而不是被分解。
我已经确认我的解构代码正在执行。例如,我可以在属性名周围手动添加引号,但这只会在内部值中产生更多转义引号
我自己的代码直接从C#解构它。我认为这可能是我的解构代码中的一个bug,所以我四处寻找并发现了更多的问题,所以我尝试了用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类jsoneventdeststructuringpolicy:IDestructuringPolicy
{
public bool TrydStructure(对象值、ILogEventPropertyValueFactory属性值工厂、out LogEventPropertyValueResult)
{
if(值为JsonEvent JsonEvent)
{
var properties=新列表();
foreach(value.GetType().GetProperties()中的var属性)
{
var propertyValue=property.GetValue(value);
var isCollection=propertyValue为ICollection;
var isDictionary=属性值为字典;
if(isCollection)
LoggingContext.Message(“找到字典集合:“+property.Name”);
else if(isDictionary)
LoggingContext.Message(“找到的字典:“+property.Name”);
else if(property.Name.Equals(“参数”))
LoggingContext.Message(“找到的参数:+propertyValue.GetType());
if(propertyValue!=null)
添加(新的LogEventProperty(property.Name,propertyValueFactory.CreatePropertyValue(propertyValue,isCollection | | isDictionary));
}
结果=新结构值(属性);
返回true;
}
if(值为字典)
{
var properties=新列表();
foreach(字典中的var kvp)
{
如果(!string.IsNullOrWhiteSpace(kvp.Value))
添加(新的LogEventProperty(“\”+kvp.Key+“\”,propertyValueFactory.CreatePropertyValue(kvp.Value));
}
结果=新结构值(属性);
返回true;
}
结果=空;
返回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();
}
publicstaticvoid消息(JsonEvent消息)
{
Logger.ForContext(GetEnrichers(message))
.信息(信息、事件);
}
私有静态IEnumerable getEnricher(JsonEvent消息)
{
返回新列表()
.Add(“数据”,消息,真)
.Add(“CorrelationId”,ServiceTracingContext.CorrelationId)
.Add(“CorrelationDateTime”,ServiceTracingContext.CorrelationDateTime)
.Add(“RouteTemplate”,ServiceTracingContext.RouteTemplate)
.ToArray();
}
您希望被分解的东西,需要在配置中明确配置为“始终分解结构”,或者标记为{@data}
-默认情况下不会分解到每个对象对不起,我应该包含我尝试过的内容。我的代码和JSonnedDestructuringPolicy都使用propertyValueFactory.CreatePropertyValue(value,true)
,因此它被告知对值进行解构。此外,我知道它正在调用我的解构策略,因为我修改了它,在属性名称周围添加了引号,认为麋鹿把事情搞砸了,因为它不是有效的JSON。因此,正在调用destructuring类,我通过自己创建LogEventProperty列表并将其放入StructureValue中,手动创建了Destructured数据。但是,StructureValue仍然被转换为单个字符串。嗯,顶层@确实会影响分解的深度(每个类的分解策略也有深度限制)-底线是,我认为您看到的是当达到最大分解深度时会发生什么(我在谷歌上搜索serilog depth limit destructuring
或类似内容),因此该对象不在消息本身中。默认深度为5,这只是第二级,因此Serilog不应该限制它本身。我尝试手动将其设置为5。我不确定顺序是否重要,因此我将其设置在Destructure.With()的任一侧调用,但它仍然被转换为字符串。我想知道问题是否与Serilog.Enrichers.Context有关。这是否会导致深度被忽略?您希望被分解的内容需要在配置中显式配置为“always destructure”,或者标记为{@data} 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();
}