如何使用 NLog 序列化对象字段?
How to serialize object fields with NLog?
我正在测试新的 structured logging,但并没有真正弄好。
我的 nlog.config 中有这个:
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log">
<layout xsi:type="JsonLayout" includeAllProperties="true">${longdate}|${level}|${logger}|${message}</layout>
</target>
<logger name="CommunicationLogger" minlevel="Info" writeto="f"></logger>
我的日志代码如下所示:
public void LogCommunication(string operation, List<object> args)
{
var parameters = new List<object>();
var text = "Operation:{Operation} ";
parameters.Add(operation);
text += "PersonId:{PersonId} ";
parameters.Add(SharedContext.GetMyUserContext().CurrentPersonId);
text += "ClientMachineName:{ComputerName} ";
parameters.Add(SharedContext.GetMyUserContext().ClientMachineName);
text += "Servername:{MachineName} ";
parameters.Add(Environment.MachineName);
if (args != null)
{
foreach(var param in args)
{
text += "Param:{@Parameters} ";
parameters.Add(param);
}
}
_log.LogCommunication(text, parameters.ToArray());
}
public void LogCommunication(string message, params object[] args)
{
_comLogger.Log(LogLevel.Info, message, args);
}
输出看起来像这样:
{ "Operation": "OperationName", "PersonId": 1, "ComputerName":
"MyComputername", "MachineName": "MyMachinename", "Parameters":
{"LocationKeyList":[], "MyObjectIdList":[], "RolList":[]} }
我希望参数也得到序列化而不是仅仅显示 [] 这样我就可以看到服务操作的所有参数。该参数是一个复杂类型,带有 dataContract(WCF)。
是否有一种简单的方法可以使参数与结构数据一起使用。
延迟
更新1
nlog.config
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log">
<layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
</target>
设置数据的代码
var parameters = new List<object>();
var text = "{TimeStamp} - ";
parameters.Add(DateTime.Now);
text += "Duration:{Duration} ";
parameters.Add(Timestamp);
text += "Operation:{Operation} ";
parameters.Add(operation);
text += "PersonId:{PersonId} ";
parameters.Add(SharedContext.GetMyUserContext().CurrentPersonId);
text += "ClientMachineName:{ComputerName} ";
parameters.Add(SharedContext.GetMyUserContext().ClientMachineName);
text += "Servername:{MachineName} ";
parameters.Add(Environment.MachineName);
if (args != null && args.Count() > 0)
{
text += "Param:{@Parameters} ";
parameters.Add(args);
}
_log.LogCommunication(text, parameters.ToArray());
结果:
ientMachineName:\"MyComputer\" Servername:\"MyComputer\"
Param:[\"MyApp.ServiceContracts.GetEntityViewRequest\"] ",
"TimeStamp": "2020-04-08T23:30:59.7725147Z", "Duration":
"00:00:00.0009930", "Operation": "GetReferenceData", "PersonId": 1,
"ComputerName": "SE-MyCom", "MachineName": "SE-MyCom",
"Parameters": ["MyApp.ServiceContracts.GetEntityViewRequest"] }
{ "time": "2020-04-09 01:31:00.3637", "level": "Info", "message":
"2020-04-09 01:31:00 - Duration:00:00:00.5594936
Operation:\"GetExternaAnrop\" PersonId:1
ClientMachineName:\"MyComputer\" Servername:\"MyComputer\"
Param:[{\"PlaceringKeyList\":[], \"ArbetsstalleIdList\":[],
\"RollList\":[]}] ", "TimeStamp": "2020-04-08T23:31:00.363752Z",
"Duration": "00:00:00.5594936", "Operation": "GetExternaAnrop",
"PersonId": 1, "ComputerName": "SE-MyCom", "MachineName":
"SE-MyCom", "Parameters": [{"PlaceringKeyList":[],
"ArbetsstalleIdList":[], "RollList":[]}] }
更新2
我有一个如下所示的服务方法:
GetEntityViewResponse GetReferenceData(GetEntityViewRequest request);
请求 class 如下所示:
[DataContract]
public class GetEntityViewRequest
{
public GetEntityViewRequest(params EntityViewKey[] Keys)
{
EntityViewKeys.AddRange(Keys);
}
public GetEntityViewRequest(params int[] EgnaKodtyper)
{
MyList.AddRange(EgnaKodtyper);
}
public GetEntityViewRequest()
{
}
[DataMember]
public List<EntityViewKey> EntityViewKeys = new List<EntityViewKey>();
[DataMember]
public List<int> MyList= new List<int>();
}
当 运行 代码(发送请求)时,我可以在服务端的 messageInspector 中看到我获得了数据。 EntityViewKeys 有一个枚举集。
NLog 输出如下所示:
{ "time": "2020-04-12 19:27:55.6690", "level": "Info", "message":
"2020-04-12 19:27:55 - Duration:00:00:00.0034730
Operation:\"GetReferenceData\" PersonId:1
ClientMachineName:\"MyComputer\" Servername:\"MyComputer\"
Param:[\"Orbit.ServiceContracts.GetEntityViewRequest\"] ",
"TimeStamp": "2020-04-12T17:27:55.6690745Z", "Duration":
"00:00:00.0034730", "Operation": "GetReferenceData", "PersonId": 1,
"ComputerName": "SE-MyCom", "MachineName": "SE-MyCom",
"Parameters": ["Orbit.ServiceContracts.GetEntityViewRequest"] }
所以即使 class 不复杂它仍然没有在 NLog 中打印内容?
JsonLayout 有一个重要的参数叫做 MaxRecursionLimit
(在 NLog v5 到来之前默认值 = 0):
https://github.com/nlog/nlog/wiki/JsonLayout
所以你可以这样做:
<layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
也许您想将参数更改为:
if (args != null)
{
text += "Params:{@Parameters} ";
parameters.Add(args);
}
NLog 默认不会序列化对象字段,而只会序列化对象属性。如果字段是必须的,那么您可以使用 NLog 4.7 设置自定义反射:
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewResponse>(obj => new {
EntityViewKeys = obj.EntityViewKeys,
MyList = obj.MyList,
})
);
或者如果你是一个懒惰的人:
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewRequest>(obj =>
return Newtonsoft.Json.Linq.JToken.FromObject(obj) // Lazy and slow
)
);
我正在测试新的 structured logging,但并没有真正弄好。
我的 nlog.config 中有这个:
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log">
<layout xsi:type="JsonLayout" includeAllProperties="true">${longdate}|${level}|${logger}|${message}</layout>
</target>
<logger name="CommunicationLogger" minlevel="Info" writeto="f"></logger>
我的日志代码如下所示:
public void LogCommunication(string operation, List<object> args)
{
var parameters = new List<object>();
var text = "Operation:{Operation} ";
parameters.Add(operation);
text += "PersonId:{PersonId} ";
parameters.Add(SharedContext.GetMyUserContext().CurrentPersonId);
text += "ClientMachineName:{ComputerName} ";
parameters.Add(SharedContext.GetMyUserContext().ClientMachineName);
text += "Servername:{MachineName} ";
parameters.Add(Environment.MachineName);
if (args != null)
{
foreach(var param in args)
{
text += "Param:{@Parameters} ";
parameters.Add(param);
}
}
_log.LogCommunication(text, parameters.ToArray());
}
public void LogCommunication(string message, params object[] args)
{
_comLogger.Log(LogLevel.Info, message, args);
}
输出看起来像这样:
{ "Operation": "OperationName", "PersonId": 1, "ComputerName": "MyComputername", "MachineName": "MyMachinename", "Parameters": {"LocationKeyList":[], "MyObjectIdList":[], "RolList":[]} }
我希望参数也得到序列化而不是仅仅显示 [] 这样我就可以看到服务操作的所有参数。该参数是一个复杂类型,带有 dataContract(WCF)。
是否有一种简单的方法可以使参数与结构数据一起使用。
延迟
更新1
nlog.config
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log">
<layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
</target>
设置数据的代码
var parameters = new List<object>();
var text = "{TimeStamp} - ";
parameters.Add(DateTime.Now);
text += "Duration:{Duration} ";
parameters.Add(Timestamp);
text += "Operation:{Operation} ";
parameters.Add(operation);
text += "PersonId:{PersonId} ";
parameters.Add(SharedContext.GetMyUserContext().CurrentPersonId);
text += "ClientMachineName:{ComputerName} ";
parameters.Add(SharedContext.GetMyUserContext().ClientMachineName);
text += "Servername:{MachineName} ";
parameters.Add(Environment.MachineName);
if (args != null && args.Count() > 0)
{
text += "Param:{@Parameters} ";
parameters.Add(args);
}
_log.LogCommunication(text, parameters.ToArray());
结果:
ientMachineName:\"MyComputer\" Servername:\"MyComputer\" Param:[\"MyApp.ServiceContracts.GetEntityViewRequest\"] ", "TimeStamp": "2020-04-08T23:30:59.7725147Z", "Duration": "00:00:00.0009930", "Operation": "GetReferenceData", "PersonId": 1, "ComputerName": "SE-MyCom", "MachineName": "SE-MyCom", "Parameters": ["MyApp.ServiceContracts.GetEntityViewRequest"] }
{ "time": "2020-04-09 01:31:00.3637", "level": "Info", "message": "2020-04-09 01:31:00 - Duration:00:00:00.5594936 Operation:\"GetExternaAnrop\" PersonId:1 ClientMachineName:\"MyComputer\" Servername:\"MyComputer\" Param:[{\"PlaceringKeyList\":[], \"ArbetsstalleIdList\":[], \"RollList\":[]}] ", "TimeStamp": "2020-04-08T23:31:00.363752Z", "Duration": "00:00:00.5594936", "Operation": "GetExternaAnrop", "PersonId": 1, "ComputerName": "SE-MyCom", "MachineName": "SE-MyCom", "Parameters": [{"PlaceringKeyList":[], "ArbetsstalleIdList":[], "RollList":[]}] }
更新2
我有一个如下所示的服务方法:
GetEntityViewResponse GetReferenceData(GetEntityViewRequest request);
请求 class 如下所示:
[DataContract]
public class GetEntityViewRequest
{
public GetEntityViewRequest(params EntityViewKey[] Keys)
{
EntityViewKeys.AddRange(Keys);
}
public GetEntityViewRequest(params int[] EgnaKodtyper)
{
MyList.AddRange(EgnaKodtyper);
}
public GetEntityViewRequest()
{
}
[DataMember]
public List<EntityViewKey> EntityViewKeys = new List<EntityViewKey>();
[DataMember]
public List<int> MyList= new List<int>();
}
当 运行 代码(发送请求)时,我可以在服务端的 messageInspector 中看到我获得了数据。 EntityViewKeys 有一个枚举集。
NLog 输出如下所示:
{ "time": "2020-04-12 19:27:55.6690", "level": "Info", "message": "2020-04-12 19:27:55 - Duration:00:00:00.0034730 Operation:\"GetReferenceData\" PersonId:1 ClientMachineName:\"MyComputer\" Servername:\"MyComputer\" Param:[\"Orbit.ServiceContracts.GetEntityViewRequest\"] ", "TimeStamp": "2020-04-12T17:27:55.6690745Z", "Duration": "00:00:00.0034730", "Operation": "GetReferenceData", "PersonId": 1, "ComputerName": "SE-MyCom", "MachineName": "SE-MyCom", "Parameters": ["Orbit.ServiceContracts.GetEntityViewRequest"] }
所以即使 class 不复杂它仍然没有在 NLog 中打印内容?
JsonLayout 有一个重要的参数叫做 MaxRecursionLimit
(在 NLog v5 到来之前默认值 = 0):
https://github.com/nlog/nlog/wiki/JsonLayout
所以你可以这样做:
<layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="10">
<attribute name="time" layout="${longdate}" />
<attribute name="level" layout="${level}"/>
<attribute name="message" layout="${message}" />
</layout>
也许您想将参数更改为:
if (args != null)
{
text += "Params:{@Parameters} ";
parameters.Add(args);
}
NLog 默认不会序列化对象字段,而只会序列化对象属性。如果字段是必须的,那么您可以使用 NLog 4.7 设置自定义反射:
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewResponse>(obj => new {
EntityViewKeys = obj.EntityViewKeys,
MyList = obj.MyList,
})
);
或者如果你是一个懒惰的人:
LogManager.Setup().SetupSerialization(s =>
s.RegisterObjectTransformation<GetEntityViewRequest>(obj =>
return Newtonsoft.Json.Linq.JToken.FromObject(obj) // Lazy and slow
)
);