如何使用Serilog.AspNetCore记录ASP.NET Core3.0的MVC属性
這是Serilog系列的第三篇文章。
第1部分-如何利用Serilog的RequestLogging來精簡ASP.NET Core的日志輸出
第2部分-Serilog高級玩法之用Serilog記錄所選終結點附加屬性
第3部分-使用Serilog.AspNetCore記錄MVC屬性(本文)
第4部分-從Serilog請求記錄中排除運行狀況檢查端點【待更新】
作者:依樂祝
譯文地址:https://www.cnblogs.com/yilezhu/p/12243984.html
原文地址:https://andrewlock.net/using-serilog-aspnetcore-in-asp-net-core-3-logging-mvc-propertis-with-serilog/
在我上篇文章中,我描述了如何配置Serilog的RequestLogging中間件以向Serilog的請求日志摘要中添加其他屬性(例如請求主機名或選定的端點名稱)。這些屬性都在HttpContext中可用,因此可以由中間件本身直接添加。
其他屬性,例如MVC特定的功能,像操作方法ID,RazorPages處理程序名稱或ModelValidationState,僅在MVC上下文中可用,因此Serilog的中間件不能直接訪問。
在本文中,我將展示如何創(chuàng)建action/page過濾器來為您記錄這些屬性,以便中間件可以在后續(xù)創(chuàng)建日志時訪問。
Serilog的創(chuàng)建者Nicholas Blumhardt之前已經解決了這個話題。解決方案非常相似,盡管他在他的示例中創(chuàng)建了一個特性,您可以使用該特性來裝飾actions/controllers。我在本文中跳過了這種方法,并要求將其全局應用,我希望這將是常見的解決方案。
記錄來自MVC的其他信息
就目前而言,ASP.NET Core中的一個特征是許多行為被MVC“基礎結構”鎖定在了MVC框架內部來實現(xiàn)。端點路由是采用MVC功能并將其下移到核心框架中的首要工作之一。ASP.NET Core團隊一直在努力將更多MVC特定功能(例如模型綁定或操作結果)從MVC中移除,然后“下推”到核心框架中。有關此內容的更多信息,請參見Ryan Nowak在NDC上對Houdini項目的討論。
但是,就目前情況而言,MVC內仍然存在一些不容易從應用程序其他部分訪問的特性。當我們考慮到我們的Serilog的請求記錄中間件的時候,這意味著有些屬性我們也是不容易記錄的。例如:
HandlerName(OnGet)
ActionId(1fbc88fa-42db-424f-b32b-c2d0994463f1)
ActionName (MyController.SomeApiMethod (MyTestApp))
RouteData({action = "SomeApiMethod", controller = "My", page = ""})
ValidationState(True/?False)
在上一篇文章中我展示了如何使用RequestLogging中間件的擴展方法通過使用IDiagnosticContext將附加屬性寫入Serilog的請求日志中。這也僅適用于在HttpContext可用的值。在這篇文章中,我將展示如何在過濾器中使用IDiagnosticContext,以及將MVC特定值添加到日志中。我還將展示如何在page過濾器中添加RazorPages特定的值(如HandlerName)。
使用自定義過濾器記錄MVC屬性
過濾器相當于為每個請求運行的類似于MVC的微型中間件管道。.NET Core MVC中有多種類型的過濾器,每種類型的過濾器在MVC過濾器管道中的有著不同的用途(有關更多詳細信息,請參見此文章)。在本文中,我們將使用最常見的過濾器之一,即Action過濾器。
Action過濾器在執(zhí)行MVC操作方法之前和之后運行。他們可以訪問許多MVC屬性的值,例如正在執(zhí)行的Action及其將被調用的參數(shù)。
下面的Action過濾器直接實現(xiàn)IActionFilter。該OnActionExecuting方法在調用action方法之前被調用,并將額外的MVC特定屬性添加到通過構造函數(shù)傳入的IDiagnosticContext中。
public class SerilogLoggingActionFilter : IActionFilter{private readonly IDiagnosticContext _diagnosticContext;public SerilogLoggingActionFilter(IDiagnosticContext diagnosticContext){_diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext));}public void OnActionExecuting(ActionExecutingContext context){_diagnosticContext.Set("RouteData", context.ActionDescriptor.RouteValues);_diagnosticContext.Set("ActionName", context.ActionDescriptor.DisplayName);_diagnosticContext.Set("ActionId", context.ActionDescriptor.Id);_diagnosticContext.Set("ValidationState", context.ModelState.IsValid);}// Required by the interfacepublic void OnActionExecuted(ActionExecutedContext context){}}在將MVC服務添加到應用程序中時,可以在以下位置全局注冊過濾器Startup.ConfigureServices():
public void ConfigureServices(IServiceCollection services) {services.AddControllers(opts =>{opts.Filters.Add<SerilogLoggingPageFilter>();});// ... other service registration }無論你使用AddControllers,AddControllersWithViews,AddMvc,或AddMvcCore的方式你都可以采用同樣的方式來添加全局過濾器。
有了這個配置之后,如果你調用一個MVC控制器,你在Serilog的請求日志消息中會看到額外的數(shù)據(ActionName,ActionId,和RouteData,ValidationState)記錄:
您可以在此處將所需的任何其他數(shù)據添加到日志中。只需注意記錄參數(shù)值-切記不要記錄敏感或個人身份信息!
Nicholas Blumhardt在他的帖子中建議的Action過濾器是從ActionFilterAttribute派生的,因此可以將其直接用作控制器和Action的特性。不幸的是,這意味著您必須使用服務定位來從每個請求的HttpContext中檢索單例的IDiagnosticContext。我的方法可以改用構造函數(shù)注入,但是不建議將其用作屬性,因此必須如上所述全局使用。而且,MVC將在我的實現(xiàn)中使用作用域生存期,而不是單例,因此它會在每個請求中創(chuàng)建一個新實例。
如果要記錄其他集中MVC過濾器中的值,則可以以相同的方式實現(xiàn)其他過濾器,例如資源過濾器,結果過濾器或授權過濾器。
使用自定義page過濾器記錄RazorPages屬性
上面實現(xiàn)的IActionFilter過濾器在MVC和API控制器上能夠正常運行,但它不會對RazorPages起作用。如果要為選擇的給定Razor頁面記錄HandlerName,則需要創(chuàng)建一個自定義的IPageFilter。
頁面過濾器直接類似于Action過濾器,但它們僅適用于Razor頁面。以下示例從PageHandlerSelectedContext中檢索處理程序名稱并將其記錄為屬性RazorPageHandler。在這種情況下,還需要一些樣板代碼,但過濾器的功能還是非常基礎的-調用IDiagnosticContext.Set()以記錄屬性。
public class SerilogLoggingPageFilter : IPageFilter{private readonly IDiagnosticContext _diagnosticContext;public SerilogLoggingPageFilter(IDiagnosticContext diagnosticContext){_diagnosticContext = diagnosticContext ?? throw new ArgumentNullException(nameof(diagnosticContext));}//Required by the interfacepublic void OnPageHandlerExecuted(PageHandlerExecutedContext context){}public void OnPageHandlerExecuting(PageHandlerExecutingContext context){}public void OnPageHandlerSelected(PageHandlerSelectedContext context){var name = context.HandlerMethod?.Name ?? context.HandlerMethod?.MethodInfo.Name;if (name != null){_diagnosticContext.Set("RazorPageHandler", name);}}}請注意,我們之前編寫的IActionFilter代碼不會在Razor Pages上運行,因此,如果您也想記錄RazorPages?RouteData或ValidationStateRazorPages的其他詳細信息,則也需要在此處添加它。該context屬性包含您可能需要的大多數(shù)屬性,例如ModelState和ActionDescriptor。
接下來,您需要在Startup.ConfigureServices()方法中注冊頁面過濾器:
public void ConfigureServices(IServiceCollection services){//services.AddMvcCore(// opts => opts.Filters.Add<SerilogLoggingPageFilter>()// );services.AddRazorPages().AddMvcOptions(opts => opts.Filters.Add<SerilogLoggingPageFilter>()) ;}添加過濾器后,對“Razor頁面”的請求現(xiàn)在可以看到添加的附加屬性,IDiagnosticContext這些屬性將添加到Serilog請求日志中。請參見下圖中的RazorPageHandler屬性:
總結
默認情況下,當用Serilog的請求日志記錄中間件替換ASP.NET Core基礎結構中的日志記錄時,您會丟失一些信息(與開發(fā)環(huán)境的默認配置相比)。在本文中,我將展示如何自定義Serilog,RequestLoggingOptions以重新添加特定于MVC的其他屬性。
要將與MVC相關的屬性添加到Serilog請求日志中,請創(chuàng)建一個IActionFilter并使用IDiagnosticContext.Set()來添加屬性。要將與Razor頁面相關的屬性添加到Serilog請求日志中,請在IPageFilter中使用IDiagnosticContext的相同方法創(chuàng)建和添加屬性。
下一節(jié)讓我們一起探討下如何從Serilog請求記錄中排除運行狀況檢查端點。
總結
以上是生活随笔為你收集整理的如何使用Serilog.AspNetCore记录ASP.NET Core3.0的MVC属性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用BeetleX.NetBenchma
- 下一篇: 各互联网公司延期上班一览