【小作業】為NLog自定義LayoutRenderer
長話短說
前文《解剖HttpClientFactory,自由擴充套件HttpMessageHandler》主要想講如何擴充套件HttpMessageHandler, 示例為在每個Http請求中的日誌中顯示TraceId,
現在來完成課後的小作業: 將TraceId顯示到Nlog的LayoutRenderer上。
本次重新實現一個流暢簡單的 LoggingHttpMessageHandler, 並新增到NLog LayoutRenderer。
什麼是Layout Renderer?
nlog 日誌上顯示的特定欄位,便於檢索和分類。
頭腦風暴
先給出自定義Renderer,定義名為eqid的自定義Renderer
# 擷取自 nlog.config配置檔案 <variable name="format1" value="${date:format=yy/MM/dd HH\:mm\:ss} [${level}].[${logger}].[${threadid}}].[${aspnet-request-url:IncludeScheme=false:IncludeHost=false}].[${eqid}]${newline}${message} ${exception:format=tostring}" /> <target name="bce-request" xsi:type="File" layout="${format1}" fileName="${logDir}/bce-request.log" encoding="utf-8"/>
-------------------------------1----------------------------
Nlog 新增自定義LayOutRenderer, https://github.com/NLog/NLog/wiki/How-to-write-a-custom-layout-renderer
有簡單的lambda方式,這裡我們採用稍微靈活的自定義類方式:
[LayoutRenderer("eqid")] public class EqidLayoutRenderer : LayoutRenderer { protected override void Append(StringBuilder builder, LogEventInfo logEvent) { builder.Append(logEvent.Properties["EventId_Name"].ToString()); } }
關鍵點是實現 LayoutRenderer 的抽象方法 Append, 關鍵引數logevent由寫入Logging時形成。
從EventId.Name中為eqid renderer取值的原因如步驟2
---------------------------------2-----------------------------
配合著,我們在寫入日誌時, 也在該property 中寫入該Renderer的值:
public class AttachTraceIdScopeHttpMessageHandler : DelegatingHandler { private readonly ILogger _logger; public AttachTraceIdScopeHttpMessageHandler(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var stopwatch = Stopwatch.StartNew(); var eventName = request.RequestUri.LocalPath.Split('/').LastOrDefault(); _logger.Log(LogLevel.Information, new EventId(100, eventName), $"Start processing HTTP request {request.RequestUri} {request.Method}"); var response = await base.SendAsync(request, cancellationToken); stopwatch.Stop(); _logger.Log(LogLevel.Information, new EventId(101, eventName), $"End processing HTTP request after {stopwatch.Elapsed.TotalMilliseconds}ms - {response.StatusCode}"); return response; } }
EventId 中的Name屬性,最後在 nlog的 EventLogInfo中被認定為 Property[EventId_Name], 所以我們有以上操作。
按照上文方式,新增到 CustomHttpMessageHandlerFilter,並註冊為 IHttpMessageHandlerFilter 實現。
--------------------------------3------------------------
按照文件的要求,儘量早點註冊自定義Nlog LayoutRenderer,
因此我在 main函式開始的時候就註冊了該Renderer, 註冊名稱是TraceId
public static void Main(string[] args) { LayoutRenderer.Register<EqidLayoutRenderer>("eqid"); ...... }
最終輸出如下:
19/12/07 00:35:42 [Info].[System.Net.Http.HttpClient.bce-request.LogicalHandler].[19}].[].[125aa91f0011426c000000045dea5ea0] Start processing HTTP request http://localhost:5000/v1/eqid/125aa91f0011426c000000045dea5ea0 GET 19/12/07 00:35:44 [Info].[System.Net.Http.HttpClient.bce-request.LogicalHandler].[5}].[].[125aa91f0011426c000000045dea5ea0] End processing HTTP request after 2178.9971ms - OK
ok, 執行本文示例,請務必參閱 《解剖HttpClientFactory,自由擴充套件HttpMessageHandler》思路,本文主要目的是講解 自定義Nlog LayoutRenderer.
&n