簡體   English   中英

是否可以在沒有模板消息的情況下使用NLog的結構化日志記錄?

[英]Is it possible to use NLog's structured logging without having templated messages?

直到今天,我們仍使用NLog 4.4.12版(不使用結構化日志記錄)。 但是,我們使用https://www.nuget.org/packages/NLog.StructuredLogging.Json/進行結構化日志記錄。

使用此擴展的好處是您不需要模板消息(包含索引或占位符以記錄其他參數/​​對象)。 該消息不包含要記錄的其他對象(即匿名類型)的任何索引或占位符。

切換到支持結構化登錄的NLog 4.6.5時,我們希望擺脫該附加的NuGet包。 但是,僅當使用帶有實際索引/命名占位符的模板消息時,才會記錄我們的附加參數。

我們的消息中沒有索引或占位符會導致沒有其他參數/​​對象通過JSON呈現出來。

是否有可能使用非模板消息,但是仍使用NLog的結構化日志記錄我們傳遞給他們的其他參數,以便將它們添加到JSON中?

下面是一個示例(請注意,我們在nlog周圍使用了額外的包裝器)

NLog版本 :4.6.5

平台 :.Net 4.5

當前的NLog配置

// Arrange
var typeUsingLogger = typeof(NLogWrapperTest);
var nLogWrapper = new NLogWrapper(typeof(NLogWrapper));

var level = (LogLevel)Enum.Parse(typeof(LogLevel), nLevel.Name);
var message = $"{Guid.NewGuid()}"; // {{extendedLogProperties}}  {{@extendedLogProperties}} {{@purchase}} {{badplaceholder}}
var innerException = new DivideByZeroException("bla inner exception");
var exception = new ArgumentNullException("bla out exception", innerException);
var extendedLogProperties = new
{
    ClientID = 8,
    MyOtherProp = "abc",
    MySubObject = new
    {
        //nested object although not recommended
        A = 123,
        B = "yep"
    }
};

//log configuration
var logConfig = new LoggingConfiguration();

var memoryTarget = new MemoryTarget("MemoryTarget");
var jsonLayout = new JsonLayout
{
    IncludeAllProperties = true,
    Attributes =
    {
            new JsonAttribute("dateTime", "${date:universalTime=true:format=o}" ),
            new JsonAttribute("level", "${level:uppercase=true}" ),
            new JsonAttribute("logger", "${logger}" ),
            new JsonAttribute("message", "${message}" ),
            new JsonAttribute("callsite", "${callsite:className=true:methodName=true:skipFrame=0}" ),
            new JsonAttribute("exception", "${exception:format=ToString:innerFormat=ToString}" ),
            new JsonAttribute("machinename", "${machinename}" ),
            new JsonAttribute("processid", "${processid}" ),
            new JsonAttribute("threadid", "${threadid}" ),
            new JsonAttribute("threadname", "${threadname}" ),
            new JsonAttribute("application", "${application}" ),
            new JsonAttribute("aspnetSessionId", "${aspnet-sessionid}" ),
            new JsonAttribute("iisSiteName", "${iis-site-name}" ),
            new JsonAttribute("stage", "${stage}" ),
    }
};
memoryTarget.Layout = jsonLayout;
logConfig.AddTarget("memoryTarget", memoryTarget);
var memoryTargetLoggingRule = new LoggingRule("*", nLevel, memoryTarget);
logConfig.LoggingRules.Add(memoryTargetLoggingRule);

LogManager.Configuration = logConfig;

// Act
nLogWrapper.Log(level, message, typeUsingLogger, exception, extendedLogProperties);

var jsonLogMsg = memoryTarget.Logs[0];
Assert.Matches("ClientID", jsonLogMsg);

我們為什么需要它?

  • 如果沒有任何替換的索引或占位符,則使消息不變就好了,這樣我們就可以在日志中搜索完全相同的消息。 (不能使用new JsonAttribute("message", "${message:raw=true}"

  • 同樣,通過這種方式,我們也不會最終在日志消息(替換模板消息的占位符/索引)和這些附加參數的附加JSON字段中使JSON序列化對象一次。

請查看其最佳做法: https : //github.com/justeat/NLog.StructuredLogging.Json/blob/master/README.md#best-practices

如果您問:“為什么不繼續使用NuGet NLog擴展?” 答案是,當在嵌套對象的模板消息中使用{@placeholder}時,NLog的結構化日志會更好地呈現其他參數。

編輯1:我想將匿名對象的所有屬性呈現在json的根目錄中。 如:

{
    ...
    "ClientID": 8,
    "MyOtherProp": "abc",
    "MySubObject": {              
                    "A": 123,
                    "B": "yep"
                },
    ...
}

我認為您正在尋找logger.WithProperty

例:

var extendedLogProperties = new
{
    ClientID = 8,
    MyOtherProp = "abc",
    MySubObject = new
    {
        //nested object although not recommended
        A = 123,
        B = "yep"
    }
};

logger.WithProperty("extendedLogProperties", extendedLogProperties).Info("test message");

您可以將其序列化為JSON,XML等。

示例,帶有所有屬性的JSON

將所有事件屬性呈現為JSON

配置:

 <target xsi:type="File" name="jsonFile" 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="2"/>
         </attribute>
     </layout>
 </target>

重要的是includeAllProperties="true"maxRecursionLimit="2" (默認為0 )。 請參閱Json Layout文檔

這應該呈現(演示的格式很好,但是將是一行):

{
    "time": "2019-06-18 11:09:00.2349",
    "level": "Info",
    "message": "test message",
    "eventProperties": {
        "extendedLogProperties": {
            "ClientID": 8,
            "MyOtherProp": "abc",
            "MySubObject": {
                "A": 123,
                "B": "yep"
            }
        }
    }
}

筆記

因此要明確:

JSON將寫在一行上,因此沒有換行符。

在我的包裝中,我設法實現了這樣的目標:

        private void Log(
            NLog.LogLevel nlogLogLevel,
            Logger nlogLogger,
            Type typeUsingLogger,
            string message,
            Exception exception,
            IDictionary<string, object> additionalProperties = null)
        {
            var logEventInfo = new LogEventInfo(nlogLogLevel, typeUsingLogger.ToString(), null, message, new object[] { }, exception);
            if (additionalProperties != null)
            {
                foreach (var x in additionalProperties)
                {
                    if (!logEventInfo.Properties.ContainsKey(x.Key))
                    {
                        logEventInfo.Properties.Add(x.Key, x.Value);
                    }
                }
            }

            nlogLogger.Log(_logWrapperType, logEventInfo);
        }

並將includeAllProperties設置為true ,並將maxRecursionLimit設置更高(2)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM