.NET Core整合CorrelationId實現全鏈路日誌輸出

w發表於2020-12-16

.NET Core整合CorrelationId實現全鏈路日誌輸出

一,鏈路追蹤

隨著微服務架構的流行,一次請求會涉及多個服務的呼叫,並且服務本身也可能會依賴其他服務,整個請求路徑會構成一個呼叫鏈,當某個節點發生異常時,整個呼叫鏈的穩定性都會受到影響,由此APM(應用效能管理)應運而生。

APM可以用於分散式追蹤、效能指標分析、應用和服務依賴分析等,可以幫助理解系統行為和分析效能問題。

常見的APM有SkyWalking,Cat、Zipkin、Pinpoint等。其中,SkyWalking可以通過SkyAPM-dotnet整合,Zipkin可以通過zipkin4net整合,對SkyWalking有興趣的童鞋可以看我另外一篇文章《.NET Core整合SkyWalking+SkyAPM-dotne實現分散式鏈路追蹤》。

雖然APM可以捕捉到整個鏈路請求,但個人感覺在日誌層面還是比較薄弱,更多的還是用於效能分析和追蹤。

在實際的生產應用中,大部分的異常更多的是業務異常,APM並不能對日誌的定位尋找產生太大幫助,最好的方案還是在日誌中輸出請求鏈路的唯一標識,利用唯一標識,我們可以很容易的在日誌中心中把請求鏈路的所有日誌檢索出來。

二,CorrelationId

CorrelationId會在請求中產生一個唯一標識,並可以將唯一標識作為一個Header傳遞到下一請求,以此類推,從而整個鏈路都可以獲取到這個標識,並自主列印到日誌當中。

下面來看一下詳細的實現:

安裝nuget包CorrelationId

修改Startup.cs

1.注入元件,可不宣告option,UpdateTraceIdentifier = true會自動更新httpcontext中TraceIdentifier欄位

 1 services.AddDefaultCorrelationId(options =>
 2             { 
 3                 //options.CorrelationIdGenerator = () => "Foo";
 4                 //options.AddToLoggingScope = true;
 5                 //options.EnforceHeader = true;
 6                 //options.IgnoreRequestHeader = false;
 7                 //options.IncludeInResponse = true;
 8                 //options.RequestHeader = "My-Custom-Correlation-Id";
 9                 //options.ResponseHeader = "X-Correlation-Id";
10                 options.UpdateTraceIdentifier = true;
11             });

2.同一鏈路中所有節點需宣告同一個Client名稱,加入此句才能將CorrelationId傳遞出去

 services.AddHttpClient("MyClient")
         .AddCorrelationIdForwarding()

3.

app.UseCorrelationId();

到此,單個應用節點就已經配置完成了,是不是so easy。同理,其他應用節點也是這麼配置。

下面,我們來使用這個唯一標識

宣告ICorrelationContextAccessor物件,並通過建構函式注入

public class TransientClass
{
   private readonly ICorrelationContextAccessor _correlationContext;

   public TransientClass(ICorrelationContextAccessor correlationContext)
   {
      _correlationContext = correlationContext;
   }
   
    ...
}

通過_correlationContextAccessor物件即可獲取到唯一標識,後續輸出日誌時,便可列印出來

_logger.LogInformation($"[{_correlationContextAccessor.CorrelationContext.CorrelationId}]我是A");

需要特別注意的是,如呼叫的是gRPC服務,header預設是空的,無法通過配置直接帶過去,需要手動傳遞

 var header = new Grpc.Core.Metadata { { "X-Correlation-Id", _correlationContextAccessor.CorrelationContext.CorrelationId } };
 return await _queryClient.GetListAsync(request, header);

如設定UpdateTraceIdentifier = true,也可直接獲取HttpContext中TraceIdentifier的欄位,兩者值是一樣的

 _logger.LogInformation($"[{context.GetHttpContext().TraceIdentifier}]我是B");

最後,讓我們看一下日誌輸出的效果:

附上GitHub中詳細的使用文件:https://github.com/stevejgordon/CorrelationId/wiki

相關文章