【问题标题】:How to serialize object fields with NLog?如何使用 NLog 序列化对象字段?
【发布时间】:2020-04-08 14:56:27
【问题描述】:

我正在测试新的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": “我的计算机名”、“机器名”:“我的机器名”、“参数”: {"LocationKeyList":[], "MyObjectIdList":[], "RolList":[]} }

我希望参数也得到序列化,而不是仅仅 showint [],这样我就可以看到服务操作的所有参数。参数是带有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\" 服务器名:\"MyComputer\" 参数:[\"MyApp.ServiceContracts.GetEntityViewRequest\"] ", “时间戳”:“2020-04-08T23:30:59.7725147Z”,“持续时间”: “00:00:00.0009930”,“操作”:“GetReferenceData”,“PersonId”:1, “计算机名”:“SE-MyCom”,“机器名”:“SE-MyCom”, “参数”:[“MyApp.ServiceContracts.GetEntityViewRequest”] }

{ “时间”:“2020-04-09 01:31:00.3637”,“级别”:“信息”,“消息”: “2020-04-09 01:31:00 - 持续时间:00:00:00.5594936 操作:\"GetExternaAnrop\" PersonId:1 ClientMachineName:\"MyComputer\" 服务器名:\"MyComputer\" 参数:[{\"PlaceringKeyList\":[], \"ArbetsstalleIdList\":[], \"RollList\":[]}]", "时间戳": "2020-04-08T23:31:00.363752Z", “持续时间”:“00:00:00.5594936”,“操作”:“GetExternaAnrop”, “PersonId”:1,“计算机名”:“SE-MyCom”,“机器名”: “SE-MyCom”,“参数”:[{“PlaceringKeyList”:[], "ArbetsstalleIdList":[], "RollList":[]}] }

更新2

我有一个如下所示的服务方法:

GetEntityViewResponse GetReferenceData(GetEntityViewRequest request);

请求类如下所示:

[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 输出如下所示:

{ “时间”:“2020-04-12 19:27:55.6690”,“级别”:“信息”,“消息”: “2020-04-12 19:27:55 - 持续时间:00:00:00.0034730 操作:\"GetReferenceData\" PersonId:1 ClientMachineName:\"MyComputer\" 服务器名:\"MyComputer\" 参数:[\"Orbit.ServiceContracts.GetEntityViewRequest\"]", “时间戳”:“2020-04-12T17:27:55.6690745Z”,“持续时间”: “00:00:00.0034730”,“操作”:“GetReferenceData”,“PersonId”:1, “计算机名”:“SE-MyCom”,“机器名”:“SE-MyCom”, “参数”:[“Orbit.ServiceContracts.GetEntityViewRequest”] }

所以即使这个类并不复杂,它仍然不会在 NLog 中打印内容?

【问题讨论】:

    标签: c# .net data-structures config nlog


    【解决方案1】:

    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
       )
    );
    

    【讨论】:

    • 试过了,但没有任何区别:${level}|${logger}|${消息}
    • @Banshee 你为什么决定不复制我的建议? (删除${level}|${logger}|${message}
    • @Banshee 还要确保在进行测试运行时正在部署您更新的NLog.config
    • @Banshee 更新了我的答案,建议如何传递您的附加 args。您的原始代码为所有 args 元素重用了相同的参数名称。
    • @Banshee 认为您必须显示您隐藏在名为 args 的包中的对象类型。 args 中的每个对象都有一个属性,属性的类型是一个不包含任何元素的数组。但感觉就像你看到他们有更多的内容,但我不是通灵者。
    猜你喜欢
    • 1970-01-01
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多