1. 程式人生 > >ASP.NET Core應用中如何記錄和檢視日誌

ASP.NET Core應用中如何記錄和檢視日誌

日誌記錄不僅對於我們開發的應用,還是對於ASP.NET Core框架功能都是一項非常重要的功能特性。我們知道ASP.NET Core使用的是一個極具擴充套件性的日誌系統,該系統由Logger、LoggerFactory和LoggerProvider這三個核心物件組成。我們可以通過簡單的配置實現對LoggerFactory的定製,以及對LoggerProvider新增。 [ 本文已經同步到《ASP.NET Core框架揭祕》之中]

目錄
一、 配置LoggerFactory
二、以當前請求作為日誌範圍
三、記錄異常日誌

一、 配置LoggerFactory

我們在上面一節演示了一個展示ASP.NET Core預設註冊服務的例項,細心的讀者一定會看到顯示的列表中就包含了針對LoggerFactory的服務。如果這個預設的LoggerFactory服務不能滿足我們的需求,我們完全可以配置任何一個需要的LoggerFactory,針對LoggerFactory的設定可以直接呼叫WebHostBuilder的UseLoggerFactory方法來實現。

   1: public interface IWebHostBuilder
   2: {
   3:     IWebHostBuilder UseLoggerFactory(ILoggerFactory loggerFactory);
   4:     IWebHostBuilder ConfigureLogging(Action<ILoggerFactory> configureLogging);
   5:     ...
   6: }

不過針對日誌的配置更多地還是體現在針對某種LoggerProvider的新增,而這可以通過呼叫WebHostBuilder的ConfigureLogging方法來完成。我們在上面演示的例項中就曾經採用如下的方式將一個ConsoleLoggerProvider註冊到LoggerFactory之上,這樣我們可以直接在宿主應用的擴展臺上看到記錄的日誌資訊。

   1: new WebHostBuilder()
   2:     .ConfigureLogging(factory=>factory.AddConsole())
   3:     ...

既然LoggerFactory已經作為一個服務進行了註冊,那麼我們完全按照依賴注入的來獲取這個物件,並利用它建立對應的Logger物件來寫日誌。如果我們需要在一個定義的中介軟體中寫入某種型別的日誌,就可以按照如下的方式在Invoke方法中定義ILoggerFactory型別的引數注入這個LoggerFactory。

   1: public class FoobarMiddleware
   2: {
   3:     private RequestDelegate _next;
   4:  
   5:     public FoobarMiddleware(RequestDelegate next)
   6:     {
   7:         _next = next;
   8:     }
   9:  
  10:     public async Task Invoke(HttpContext context, ILoggerFactory loggerFactory)
  11:     {
  12:         ILogger<FoobarMiddleware> logger = loggerFactory.CreateLogger<FoobarMiddleware>();
  13:         logger.LogInformation("...");
  14:         await _next(context);
  15:     }
  16: }

不僅僅我們開發的應用或者中介軟體可以利用註冊的LoggerFactory來建立進行日誌記錄的Logger物件,ASP.NET Core管道本身也會在處理請求過程中採用相同的方式記錄一些日誌。比如管道每次處理請求的開始和結束時候分別會寫入兩條Information等級的日誌,我們現在就來通過一個簡單的例項看看這兩條日誌資訊具有怎樣的內容。

   1: public class Program
   2: {
   3:     public static void Main()
   4:     {
   5:         new WebHostBuilder()
   6:             .ConfigureLogging(factory=>factory.AddConsole())
   7:             .UseKestrel()
   8:             .UseStartup<Startup>()                
   9:             .Build()
  10:             .Run();
  11:     }
  12: }
  13:  
  14: public class Startup
  15: {
  16:     public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
  17:     {
  18:         app.Run(async context =>
  19:         {
  20:             loggerFactory.CreateLogger("App").LogInformation("Log entry for test...");
  21:             await context.Response.WriteAsync("Hello world!");
  22:         });
  23:     }
  24: }

如上所示的程式碼有兩處與日誌有關,第一個地方是呼叫WebHostBuilder的ConfigureLogging方法通過呼叫擴充套件方法AddConsole將一個ConsoleProvider新增到當前LoggerFactory之上,另一個地方就是啟動類的Configure方法註冊的中介軟體在執行過程中會利用注入的LoggerFactory建立一個Logger物件,我們利用後者寫入了一條Information等級的日誌。我們執行程式之後利用瀏覽器訪問目標地址後,宿主控制檯上會出現如下圖所示的三條日誌。除了第二條日誌是由我們自己編寫的程式碼寫入的之外,其餘兩條都是ASP.NET Core框架自己寫入的。第一條日誌包含不僅僅包含請求的目標地址,還包括請求採用的協議(HTTP/1.1)和HTTP方法(GET),第三條則反映了整個請求處理過程所花的時間。

6

由於ASP.NET Core管道對請求的處理總是在一個由HttpApplication建立的執行上下文中進行,所以上下文的建立和回收釋放可以視為 整個請求處理流程開始和結束的標識。對於上述的這兩條分別在處理請求開始和結束時寫入的日誌,實際上是在HostingApplication的CreateContext和DisposeContext方法分別被呼叫的時候被記錄下來的。之所以在結束的時候能夠計算出整個請求處理過程所花的時間,是因為建立的這個上下文物件儲存了開始處理請求的時間戳,該時間戳對應著Context結構的StartTimestamp屬性。

   1: public class HostingApplication : IHttpApplication<HostingApplication.Context>
   2: {
   3:     public struct Context
   4:     {
   5:         public HttpContext      HttpContext { get; set; }
   6:         public IDisposable      Scope { get; set; }
   7:         public long          StartTimestamp { get; set; }
   8:     }
   9: }

二、以當前請求作為日誌範圍

我們知道日誌系統有一個叫做“日誌範圍”的概念,它的目的在於為多次相關的日誌記錄建立一個上下文範圍,併為這個範圍提供一個唯一標識,這個標識會作為日誌內容的一部分被寫入。當我們在進行日誌分析的時候,可以根據日誌範圍標識將一組原本獨立的日誌關聯起來。這個概念對於Web應用尤為重要,因為很多情況下我們所做的日誌分析都是針對某一個請求,這就要求我們必須明確地分辨出被記錄下來的日誌隸屬於哪一個請求,只有這樣才能將針對同一請求的所有日誌提取出來做綜合的分析以得出一個準確的結論。

從上個例項最終寫入的三條日誌來看,它們並不攜帶當前請求的標識資訊。但是這不是ASP.NET Core的問題,而是我們在呼叫LoggerFactory的擴充套件方法AddConsole註冊ConsoleLoggerProvider的時候並未顯式開啟針對日誌範圍的支援。為了讓註冊的ConsoleLoggerProvider建立的Logger能夠支援日誌範圍,我們只需按照如下的方式在呼叫AddConsole方法的時候新增一個額外的引數(true)即可。

   1: new WebHostBuilder()
   2:     .ConfigureLogging(factory=>factory.AddConsole(true))
   3:     .UseKestrel()
   4:     .UseStartup<Startup>()                
   5:     .Build()
   6:     .Run();

我們再次請求應用並利用瀏覽器對目標地址傳送兩次請求,六條寫入的日誌將會以如下圖所示的形式輸出到控制檯上。不同於上面的輸出結果,本次輸出的日誌包含請求的ID(Request Id),在同一個請求下被記錄下來的日誌具有相同的ID。除了請求ID,記錄的日誌還攜帶了請求的路徑(Request Path)。

7

日誌範圍攜帶的用於唯一標識當前請求的ID,同時也可以視為當前HttpContext的唯一標識,它對應著HttpContext的TranceIdentifier屬性。對於DefaultHttpContext來說,針對這個屬性的讀寫是藉助一個名為HttpRequestIdentifierFeature的特性實現的,下面的程式碼提供了該物件對應的介面IHttpRequestIdentifierFeature和預設實現類HttpRequestIdentifierFeature的定義。

   1: public abstract class HttpContext
   2: {
   3:     //省略其他成員
   4:     public abstract string TraceIdentifier { get; set; }
   5: }
   6:  
   7: public interface IHttpRequestIdentifierFeature
   8: {
   9:     string TraceIdentifier { get; set; }
  10: }
  11:  
  12: public class HttpRequestIdentifierFeature : IHttpRequestIdentifierFeature
  13: {
  14:     private string _id;
  15:     private static long _requestId = DateTime.UtcNow.Ticks;
  16:     private static unsafe string GenerateRequestId(long id);
  17:     public string TraceIdentifier
  18:     {
  19:         get
  20:         {
  21:             return _id??(id= GenerateRequestId(Interlocked.Increment(ref _requestId)));
  22:         }
  23:         set
  24:         {
  25:             this._id = value;
  26:         }
  27:     }
  28: }

HttpRequestIdentifierFeature生成TraceIdentifier的邏輯很簡單。如上面的程式碼片斷所示,它具有一個靜態長整型欄位_requestId,其初始值為當前時間戳。對於某個具體的HttpRequestIdentifierFeature物件來說,它的TraceIdentifier屬性的預設值返回的是這個欄位_requestId加1之後轉換的字串。具體的轉換邏輯定義在GenerateRequestId方法中,它會採用相應的演算法 將指定的整數轉換一個長度為13的字串。

和開始請求處理的時間戳一樣,被創建出來的日誌範圍實際被儲存在HostingApplication的上下文物件中,它對應著Context結構的Scope屬性。當HostingApplication建立這個Context物件的時候,它會從當前HttpContext中提取出請求的ID和路徑,創建出這個日誌範圍並賦值給這個屬性。整個請求的處理其實就在這個日誌範圍中進行,請求處理結束,當前日誌範文也被回收釋放。

   1: public class HostingApplication : IHttpApplication<HostingApplication.Context>
   2: {
   3:     public struct Context
   4:     {
   5:         public HttpContext     HttpContext { get; set; }
   6:         public IDisposable     Scope { get; set; }
   7:         public long            StartTimestamp { get; set; }
   8:     }
   9: }

三、記錄異常日誌

由於ASP.NET Core在處理請求過程中導致的異常並不會導致應用終止,考慮到安全,丟擲的異常的詳細資訊也不應該直接返回到客戶端。所以在很多情況下我們根本感知不到應用發生了異常,即使感知到了,也不知道導致異常的根源在何處。在這種情況下,我們就需要使用記錄的日誌進行差錯和糾錯,因為ASP.NET Core在處理請求遇到的異常都會記錄到日誌中。

比如針對如下這段程式,毫無疑問它針對任何一個請求的處理都會丟擲一個DivideByZeroException的異常。如果我們利用瀏覽器來訪問站點地址,它只會得到一個狀態為500的響應,並簡單的提示服務端出現錯誤。對於宿主程式來說,我們根本就是感知不到任何異常發生。

   1: new WebHostBuilder()
   2:     .UseKestrel()
            
           

相關推薦

ASP.NET Core應用如何記錄檢視日誌

日誌記錄不僅對於我們開發的應用,還是對於ASP.NET Core框架功能都是一項非常重要的功能特性。我們知道ASP.NET Core使用的是一個極具擴充套件性的日誌系統,該系統由Logger、LoggerFactory和LoggerProvider這三個核心物件組成。我們可以通過簡單的配置實現對LoggerF

ASP.NET Core應用如何設定獲取與執行環境相關的資訊?

HostingEnvironment是承載應用當前執行環境的描述,它是對所有實現了IHostingEnvironment介面的所有型別以及對應物件的統稱。如下面的程式碼片段所示,一個HostingEnvironment物件承載的執行環境的描述資訊體現在定義這個介面的6個屬性上。ApplicationName和

用最簡單的方式在ASP.NET Core應用實現認證、登入登出

在安全領域,認證和授權是兩個重要的主題。認證是安全體系的第一道屏障,是守護整個應用或者服務的第一道大門。當訪問者請求進入的時候,認證體系通過驗證對方的提供憑證確定其真實身份。認證體系只有在證實了訪問者的真實身份的情況下才會允許其進入。ASP.NET Core提供了多種認證方式,它們的實現都基於相同的認證模型。

ASP.NET Core的快取[1]:如何在一個ASP.NET Core應用使用快取

.NET Core針對快取提供了很好的支援 ,我們不僅可以選擇將資料快取在應用程序自身的記憶體中,還可以採用分散式的形式將快取資料儲存在一個“中心資料庫”中。對於分散式快取,.NET Core提供了針對Redis和SQL Server的原生支援。除了這個獨立的快取系統之外,ASP.NET Core還藉助一箇中

如何在ASP.NET Core應用實現與第三方IoC/DI框架的整合?

我們知道整個ASP.NET Core建立在以ServiceCollection/ServiceProvider為核心的DI框架上,它甚至提供了擴充套件點使我們可以與第三方DI框架進行整合。對此比較瞭解的讀者朋友應該很清楚,針對第三方DI框架的整合可以通過在定義Startup型別的ConfigureServic

ASP.NET Core 應用使用 Cookie 進行身份認證

## Overview 身份認證是網站最基本的功能,最近因為業務部門的一個需求,需要對一個已經存在很久的小工具網站進行改造,因為在逐步的將一些離散的系統遷移至 .NET Core,所以趁這個機會將這個老的 .NET Framework 4.0 的專案進行升級 老的專案是一個 MVC 的專案並且有外網訪問的

在 Azure WebApps 運行64位 Asp.net Core 應用

需求 正常 mmu www. module .config 正在 external doc 作為微軟下一代的開源的跨平臺的開發框架, Asp.net core 正在吸引越來越多的開發者基於其構建現代 web 應用。 目前, Azure App Service 也實現了對 a

ASP.NET Core應用程序部署至生產環境(CentOS7)

for linux home web 虛擬 direct director block bic 閱讀目錄 環境說明 準備你的ASP.NET Core應用程序 安裝CentOS7 安裝.NET Core SDK for CentOS7。 部署ASP.NET

在 Docker 部署 ASP.NET CORE 應用

post netcore 工作 ros core 指定 們的 本地 body 有了 Docker 之後, 部署起來卻這間非常方便,環境不用搭了, 直接創建一個 microsoft/aspnetcore 的容器, 在本地開發好後, 把內容直接部署到容器中。 下面的命令是把本

ASP.NET Core WebAPI使用JWT Bearer認證授權

目錄 為什麼是 JWT Bearer 什麼是 JWT JWT 的優缺點 在 WebAPI 中使用 JWT 認證 重新整理 Token 使用授權 簡單授權 基於固定角色的授權 基於策略的授權 自定義策略授權 基於資源的授權 原

在IIS除錯ASP.NET Core應用程式

IIS中的除錯提供了更平滑的開發過程,無需考慮您的Web伺服器是否正在執行。 我已經使用ASP.NET核心了一段時間,並且總是錯過了Visual Studio中的直接IIS支援。必須記住啟動專案才能啟動IIS Express,這有點令人討厭。在開發軟體時,我們希望實際的除錯和執行過程儘可能自

Asp.net Core全域性異常監控記錄日誌

前言           系統異常監控可以說是重中之重,系統不可能一直執行良好,開發和運維也不可能24小時盯著系統,系統拋異常後我們應當在第一時間收到異常資訊。在Asp.net Core裡我使用攔截器和中介軟體兩種方式來監控異常。全域性異常監控的資料最好還是寫入資料庫,方便查詢。 配置NLog NLog配

WTM asp.net core應用程式在Ubuntu上CentOS上部署

wtm在Ubuntu上和CentOS上部署 專案釋出 在Visual Studio中右擊Web專案,選擇釋出,如下圖: Ubuntu安裝.net core執行時 Ubuntu我是用的Vmware虛擬機器,版本是18.04 參考官方文件,如果要開發 .NET Core 應用,請安裝 SDK(包括執行時)。

15.ASP.NET Core 應用程式的靜態檔案中介軟體

在這篇文章中,我將向大家介紹,如何使用中介軟體元件來處理靜態檔案。這篇文章中,我們討論下面幾個問題:在ASP.NET Core中,我們需要把靜態檔案存放在哪裡?在ASP.NET Core中 wwwroot資料夾是啥?怎樣在ASP.NET Core應用程式中,配置靜態檔案中介軟體?UseFileServer中介

將終結點圖新增到你的ASP.NET Core應用程式

在本文中,我將展示如何使用`DfaGraphWriter`服務在ASP.NET Core 3.0應用程式中視覺化你的終結點路由。上面文章我向您演示瞭如何生成一個有向圖([如我上篇文章中所示](https://www.cnblogs.com/yilezhu/p/13301981.html)),可以使用[Grap

ASP.NET Core MVC構建簡單 Web Api

程序 Getting Started在 ASP.NET Core MVC 框架中,ASP.NET 團隊為我們提供了一整套的用於構建一個 Web 中的各種部分所需的套件,那麽有些時候我們只需要做一個簡單的 Web Api 程序怎麽辦呢?在 GitHub 中的 ASP.NET Core MVC 源碼裏面,我

Linux使用Jexus托管Asp.Net Core應用程序

技術 文件目錄 只需要 true 沒有 repr tag 博文 env 第一步 安裝.Net Core環境 安裝 dotnet 環境參見官方網站 https://www.microsoft.com/net/core。 選擇對應的系統版本進行安裝。安裝完成過後 輸入命令查

ASP.NET Core:使用DapperSwaggerUI來豐富你的系統框架

fig targe api 依賴 dev 多表 efault 方便 div 一、概述 1、用VS2017創建如下圖的幾個.NET Standard類庫,默認版本為1.4,你可以通過項目屬性進行修改,最高支持到1.6,大概五月份左右會更新至2.0,API會翻倍,很期待!

運行Vue在ASP.NET Core應用程序並部署在IIS上

生產環境 所在 來講 一個 重寫 文章 .net core 設置 分享 前言 從.NET Core 1.0開始我們就將其應用到項目中,但是呢我對ASP.NET Core一些原理也還未開始研究,僅限於會用,不過園子中已有大量文章存在,借著有點空余時間,我們來講講如何利用AS

使用Docker部署ASP.NET Core應用程序實踐

4.0 cor run .com cnblogs pda word 本地配置 問題 前言 最近把很火的Docker給看了,於是就磨拳擦掌要去實踐一下。於是就拿之前一個aps.net core的項目(已被停止)去練手。該項目之前在ubuntu14.04上確保可以正常運行,所以