[英]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
配置:
<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.