C# 如何使用NLog将未指定的对象记录到文件中,以保持ELK堆栈的兼容性?
几周来,我一直在努力让NLog记录我的通信数据,包括非特定(DataContracts)参数,并以与ELK堆栈兼容的格式归档。如果输出参数可以限制为MAX chars或depth,则需要在运行时对其进行配置 NLog有一个内置的JSON序列化程序,但它只读取没有默认值的属性,正如您所看到的,字段将被忽略。调整我的数据模型将是一项艰巨的工作,我并不认为这是正确的方法,NLog不应该影响数据模型的外观 有几种方法可以添加:C# 如何使用NLog将未指定的对象记录到文件中,以保持ELK堆栈的兼容性?,c#,logging,elastic-stack,nlog,serilog,C#,Logging,Elastic Stack,Nlog,Serilog,几周来,我一直在努力让NLog记录我的通信数据,包括非特定(DataContracts)参数,并以与ELK堆栈兼容的格式归档。如果输出参数可以限制为MAX chars或depth,则需要在运行时对其进行配置 NLog有一个内置的JSON序列化程序,但它只读取没有默认值的属性,正如您所看到的,字段将被忽略。调整我的数据模型将是一项艰巨的工作,我并不认为这是正确的方法,NLog不应该影响数据模型的外观 有几种方法可以添加: 我可以在每个类(Datacontract)上使用SetupSerializa
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewRequest>(obj =>
return Newtonsoft.Json.Linq.JToken.FromObject(obj)
)
);
_comLogger.Log(LogLevel.Info, "ComLogger : {@callInfo}", callInfo);
IValueFormatter
需要进行过滤,以便只处理来自通信记录器的数据。我可能需要用一个标志将数据包装在一个类中,该标志告诉IValueFormatter
数据来自何处,但它并不是一个最佳的解决方案
如您所见,让NLog实际输出ValueFormatter
过滤的数据也存在问题。ValueFormatter
仍在运行,但它是将在文件中结束的常规NLog JSON数据
我从NLog需要的是:
- 将所有通信数据(包括参数)从对象转换为字符串格式,以便ELK stack读取李>
- 参数上的序列化深度或字符串最大长度,以避免数据溢出
- 可在运行时从NLog.config进行配置(与NLog相同)
- 仅影响特定的NLogger实例
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewRequest>(obj =>
return Newtonsoft.Json.Linq.JToken.FromObject(obj)
)
);
_comLogger.Log(LogLevel.Info, "ComLogger : {@callInfo}", callInfo);
Nlog.config现在看起来像这样:
我错过了什么?是否还有其他日志库可以更好地支持我的需求?我认为Rolf的建议是最好的-创建一个使用JSON.NET的布局。这个人可以做所有花哨的事情,比如序列化字段和处理
[JsonIgnore]
基本版本如下所示:
使用System.Collections.Generic;
使用Newtonsoft.Json;
使用NLog;
使用NLog.Config;
使用NLog.布局;
名称空间MyNamespace
{
///
///使用Json.NET将所有属性呈现为Json,还包括消息和异常
///
[布局(“JsonNetLayout”)]
[线程不可知]//不同的线程,相同的结果
[线程安全]
公共类JSONNETLAOUT:布局
{
公共格式化格式化{get;set;}=Formatting.Indented;//可以从XML配置中设置此选项
///
受保护的重写字符串GetFormattedMessage(LogEventInfo logEvent)
{
var allProperties=logEvent.Properties??新建字典();
allProperties[“message”]=logEvent.FormattedMessage;
if(logEvent.Exception!=null)
{
allProperties[“exception”]=logEvent.exception.ToString();//ToString以防止数据属性过多
}
返回JsonConvert.SerializeObject(所有属性、格式);
}
}
}
我将使用:
Layout.Register<JsonNetLayout>("JsonNetLayout"); // namespace NLog.Layouts
这个记录器调用:
logger
.WithProperty("prop1", "value1")
.WithProperty("prop2", objectWithFieldsAndJsonStuff)
.Info("Hi");
这将导致:
{
"prop1": "value1",
"prop2": {
"_myField": "value1",
"newname": "value2"
},
"message": "Hi"
}
单元测试
所有这些都在单元测试中实现——使用xUnit
[事实]
public void JsonNetLayoutTest()
{
//安排
布局。寄存器(“JSONNETLAOUT”);
var xmlConfig=@”
";
LogManager.Configuration=XmlLoggingConfiguration.CreateFromXmlString(xmlConfig);
var logger=LogManager.GetLogger(“logger1”);
var memoryTarget=LogManager.Configuration.FindTargetByName(“target1”);
//表演
var objectwithfieldsandjsonstaff=新对象withfieldsandjsonstaff();
记录器
.WithProperty(“prop1”、“value1”)
.WithProperty(“prop2”,ObjectWithFields和JsonStuff)
.Info(“Hi”);
//断言
var actual=memoryTarget.Logs.Single();
预期风险值=
@"{
“prop1”:“value1”,
“第2项建议”:{
“”我的字段“”:“”值1“”,
“新名称”:“值2”
},
“消息”:“嗨”
}";
断言。相等(预期、实际);
}
为什么要登录到文件,而不是直接使用类似的方式将日志发送到ES。如果你有额外的属性,需要做一些重新构造/转换,你也可以将日志发送到Logstash,让它来完成所有这些…我认为该文件是这种日志记录的一个很好的缓冲区?我们也许可以做更少但更大的日志传输。但感谢您的建议,我将对此进行研究:)可能会创建一个名为NewtonsoftLayout的自定义NLog布局,允许您配置NewtonSoft JsonSerializer的操作方式。在Thankls可以找到灵感,这解决了我的问题!我需要更改为DataContractJSONSerializer,但这没关系:)