将NLog属性设置为JSON?

Jer*_*acs 4 logging serialization nlog

我试图弄清楚如何将LogEventInfo对象中的所有属性记录到JSON格式的字符串中。根据github上问题,我尝试执行以下操作:

<target xsi:type="ColoredConsole" name="coloredConsole">
  <layout xsi:type="JsonLayout">
    <attribute name="timestamp" layout="${longdate}"/>
    <attribute name="level" layout="${level:uppercase=true}"/>
    <attribute name="exception" layout="${onexception:${exception:format=tostring}}" />
    <attribute name="properties" encode="false">
      <layout type="JsonLayout">
        <attribute name="properties" layout="${all-event-properties}" />
      </layout>
    </attribute>
  </layout>
</target>
Run Code Online (Sandbox Code Playgroud)

......但不幸的是,我的属性包含复杂的对象(我有“性”和“标签”,名称两个属性,其中“性能”是一个IDictionary<string, object>和“标签”是一个IList<string>LogEventInfo.Properties属性)根本就没有连载。我最终得到类似于以下内容的内容:

{ "timestamp": "2017-05-18 08:41:28.7730", "level": "INFO", "properties": { "properties": "properties=System.Collections.Generic.Dictionary`2[System.String,System.Object], tags=System.Collections.Generic.List`1[System.String]" } }
Run Code Online (Sandbox Code Playgroud)

我期待(并希望)一个序列化的JSON字典,该字典将为我提供日志消息的上下文,但是显然,这不是我所得到的。

如何正确序列化LogEventInfo对象中的属性?

Jer*_*acs 5

好吧,看起来 NLog 中存在错误,所以我有点制作了自己的渲染器。这就是我所做的。首先,我使用 JSON.NET 做了一个扩展方法:

public static string ToJson(this object obj, bool format = false, string dateFormat = null)
{
    var settings = new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    };

    if (!String.IsNullOrWhiteSpace(dateFormat))
    {
        settings.Converters = new List<JsonConverter>
        {
            new IsoDateTimeConverter {DateTimeFormat = dateFormat}
        };

        return JsonConvert.SerializeObject(obj, format ? Formatting.Indented : Formatting.None, settings);
    }

    return JsonConvert.SerializeObject(obj, format ? Formatting.Indented : Formatting.None, settings);
}
Run Code Online (Sandbox Code Playgroud)

...接下来,我像这样创建了一个 LayoutRenderer:

[LayoutRenderer("json-event-properties")]
public class JsonEventPropertiesLayoutRenderer : LayoutRenderer
{
    /// <summary>
    /// Renders the specified environmental information and appends it to the specified <see cref="T:System.Text.StringBuilder" />.
    /// </summary>
    /// <param name="builder">The <see cref="T:System.Text.StringBuilder" /> to append the rendered data to.</param>
    /// <param name="logEvent">Logging event.</param>
    protected override void Append(StringBuilder builder, LogEventInfo logEvent) {
        if (logEvent.Properties == null || logEvent.Properties.Count == 0)
            return;
        var serialized = logEvent.Properties.ToJson();
        builder.Append(serialized);
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,启动时,我LayoutRenderer像这样注册:

LayoutRenderer.Register<JsonEventPropertiesLayoutRenderer>("json-event-properties");
Run Code Online (Sandbox Code Playgroud)

...最后,我像这样配置了 NLog 目标:

    <layout xsi:type="JsonLayout">
    <attribute name="timestamp" layout="${longdate}"/>
    <attribute name="level" layout="${level:uppercase=true}"/>
    <attribute name="exception" layout="${onexception:${exception:format=tostring}}" />
    <attribute name="message" layout="${message}" />
    <attribute name="properties" layout="${json-event-properties}" encode="false"/>
  </layout>
Run Code Online (Sandbox Code Playgroud)

像这样运行,JSON 格式正确,我可以访问LogEventInfo对象中的属性。


Căl*_*rie 5

在此处使用NLog 4.5.1。

使用此配置:

 <target xsi:type="File" name="jsonFile2" fileName="c:\temp\nlog-json-nested-${shortdate}.log">
     <layout type="JsonLayout">
         <attribute name="time" layout="${longdate}" />
         <attribute name="level" layout="${level}" />
         <attribute name="message" layout="${message}" />
         <attribute name="eventProperties" encode="false" >
             <layout type='JsonLayout' includeAllProperties="true"  maxRecursionLimit="20"/>
         </attribute>
     </layout>
 </target>
Run Code Online (Sandbox Code Playgroud)

此代码:

var nestedData = new
{
    A = "a value",
    B = "b value",
    Nested = new
    {
        A = "nested a value",
        B = "nested b value",
    },
    Ints = new Collection<int> { 1, 2, 3},
    Dictionary = new Dictionary<string, object>
    {
        {"nested", new { X= 'x', y = 'y' }},
        { "awesome", "nlog"}
    }
};
LogEventInfo eventInfo = new LogEventInfo
{
    Level = LogLevel.Info,
    Properties = { {"nestedData", nestedData } }
};
logger.Log(eventInfo);
Run Code Online (Sandbox Code Playgroud)

输出:

{  
   "time":"2018-04-05 18:08:01.0813",
   "level":"INFO",
   "eventProperties":{  
      "nestedData":{  
         "A":"a value",
         "B":"b value",
         "Nested":{  
            "A":"nested a value",
            "B":"nested b value"
         },
         "Ints":[  
            1,
            2,
            3
         ],
         "Dictionary":{  
            "nested":{  
               "X":"x",
               "y":"y"
            },
            "awesome":"nlog"
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

实际上,它会打印出丑陋的单行版本。

在NLog Wiki上查看带有结构化日志记录的嵌套JSON

注意maxRecursionLimit设置。默认情况下为0,表示“无对象反射”,表示您将获得ToString()事件属性的表示形式。