1. 程式人生 > >【小作業】為NLog自定義LayoutRenderer

【小作業】為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