这是该系列的第二篇文章:在ASP.NET Core 3.0中使用Serilog.AspNetCore。html
做者:依乐祝git
译文地址:http://www.javashuo.com/article/p-bkvxdmfz-mg.htmlgithub
在个人上一篇文章中,我描述了如何配置Serilog的RequestLogging中间件为每一个请求建立“摘要”日志,以替换默认状况下从ASP.NET Core获取的10个或更多日志。app
在本文中,我将展现如何向Serilog的摘要请求日志中添加其余元数据,例如请求的主机名,响应的内容类型或从ASP.NET Core 3.0中使用的终结点路由中间件所选择的端点名称。asp.net
正如我在上一篇文章(https://andrewlock.net/using-serilog-aspnetcore-in-asp-net-core-3-reducing-log-verbosity/)中所展现的那样,在开发环境中,ASP.NET Core基础架构将为每个RazorPage处理程序生成10条日志消息:函数
经过安装了Serilog.AspNetCore的 NuGet包后并引入RequestLoggingMiddleware
以后,能够将其精简为一条日志消息:工具
本文中使用的全部日志图片均来自一款优秀的为结构化日志提供可视化界面的工具-Sequi
显然,原始的日志集更加冗长,而且其中大部分不是特别有用的信息。可是,若是您将原始的10条日志做为一个总体来看,则与Serilog摘要日志相比,它们确实会在结构日志模板中记录一些其余属性。this
由ASP.NET Core基础结构记录的而Serilog 未记录的扩展内容包括(下面这些仍是英文的看着顺眼):
localhost:5001
)https
)HTTP/2
)test=true
)/Index
)OnGet
/SerilogRequestLogging.Pages.IndexModel.OnGet
)1fbc88fa-42db-424f-b32b-c2d0994463f1
)/Index
){page = "/Index"}
)True
/False
)PageResult
)text/html; charset=utf-8
)我认为若是要把上述属性中的其中一些包含在摘要日志消息中,将很是有用。例如,若是您的应用程序绑定到多个主机名,那么Host
绝对是重要的日志。QueryString
多是另外一个有用的字段。EndpointName
/ HandlerName
,ActionId
而且ActionName
彷佛不那么重要,由于您应该可以推断出给定的请求路径,可是显式记录它们将帮助您更加方便的捕获错误,并使过滤针对特定操做的全部请求变得更加容易。
归纳地说,您能够将这些属性分为两类:
Host
,Scheme
,ContentType
,QueryString
,EndpointName
HandlerName
,ActionId
,ActionResult
等在这篇文章中,我将展现如何添加这些类别中的第一种,即与请求/响应相关的属性,在下一篇文章中,我将展现如何添加基于MVC / RazorPages的属性。
在上一篇文章中,我展现了如何将Serilog请求日志记录添加到您的应用程序中,所以在此再也不赘述。如今,我假设您已经进行了设置,而且您拥有一个包含如下内容的Startup.Configure
方法:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... Error handling/HTTPS middleware app.UseStaticFiles(); app.UseSerilogRequestLogging(); // <-- Add this line app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); }
该UseSerilogRequestLogging()
扩展方法将Serilog RequestLoggingMiddleware
添加到请求管道中。您还能够经过调用重载来配置RequestLoggingOptions
的实例。此类具备几个属性,可让您自定义请求记录器如何生成日志语句:
public class RequestLoggingOptions { public string MessageTemplate { get; set; } public Func<HttpContext, double, Exception, LogEventLevel> GetLevel { get; set; } public Action<IDiagnosticContext, HttpContext> EnrichDiagnosticContext { get; set; } }
该MessageTemplate
属性控制将日志呈现为的字符串格式,GetLevel
容许您控制给定日志索要记录的级别,如 Debug
/ Info
/ Warning
等。这里咱们所关心的是EnrichDiagnosticContext
属性。
设置了该属性的Action<>
以后,在生成日志消息时它将被Serilog中间件调用并执行。它在日志写入以前运行,这意味着它在中间件管道执行以后运行。例如,在下图中(取自个人书《 ASP.NET Core in Action》),当响应“回传”到中间件管道时,在第5步写入日志:
在管道处理以后写入日志这一事实意味着两件事:
EndpointRoutingMiddleware
(经过UseRouting()
添加的)设置的功能:IEndpointFeature
在下一部分中,我将提供一个帮助程序功能,该功能会将全部“缺乏”属性添加到Serilog请求日志消息中。
Serilog.AspNetCore会将接口IDiagnosticContext
做为单例添加到DI容器中,所以您能够从任何类中访问它。而后,您能够调用Set()
方法,将其余属性附加到请求日志消息中。
例如,如文档所示,您能够从操做方法中添加任意值:
public class HomeController : Controller { readonly IDiagnosticContext _diagnosticContext; public HomeController(IDiagnosticContext diagnosticContext) { _diagnosticContext = diagnosticContext; } public IActionResult Index() { // The request completion event will carry this property _diagnosticContext.Set("CatalogLoadTime", 1423); return View(); } }
而后,结果摘要日志将包含属性CatalogLoadTime
。
RequestLoggingOptions
经过设置所提供IDiagnosticContext
实例的值,咱们基本上使用彻底相同的方法来定制中间件所使用的方法。下面的静态帮助器类从当前HttpContext
上下文检索值,并在值可用时对其进行设置。
下面的静态helper类从当前HttpContext检索值,并在值可用时设置它们。
public static class LogHelper { public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext) { var request = httpContext.Request; // Set all the common properties available for every request diagnosticContext.Set("Host", request.Host); diagnosticContext.Set("Protocol", request.Protocol); diagnosticContext.Set("Scheme", request.Scheme); // Only set it if available. You're not sending sensitive data in a querystring right?! if(request.QueryString.HasValue) { diagnosticContext.Set("QueryString", request.QueryString.Value); } // Set the content-type of the Response at this point diagnosticContext.Set("ContentType", httpContext.Response.ContentType); // Retrieve the IEndpointFeature selected for the request var endpoint = httpContext.GetEndpoint(); if (endpoint is object) // endpoint != null { diagnosticContext.Set("EndpointName", endpoint.DisplayName); } } }
上面的帮助器函数从“Request”,“Response”以及其余中间件(端点名称)设置的功能中检索值。您能够扩展它,以根据须要在请求中添加其余值。
您能够在你的Startup.Configure()
方法中经过调用UseSerilogRequestLogging
的EnrichDiagnosticContext
属性,来注册上面的帮助类:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... Other middleware app.UseSerilogRequestLogging(opts => opts.EnrichDiagnosticContext = LogHelper.EnrichFromRequest); // ... Other middleware }
如今,当您发出请求时,您将看到添加到Serilog结构化日志中的全部其余属性:
只要您具备经过当前HttpContext可供中间件管道使用的值,就可使用此方法。可是MVC的相关属性是个例外,它们是MVC中间件“内部”的特性,例如action 名称或RazorPage处理程序名称。在下一篇文章中,我将展现如何将它们添加到Serilog请求日志中。
默认状况下,用Serilog的请求日志记录中间件替换ASP.NET Core基础结构日志记录时,与开发环境的默认日志记录配置相比,您会丢失一些信息。在本文中,我展现了如何经过自定义Serilog RequestLoggingOptions
来添加这些附加属性。
这样的作法很是简单-您能够访问HttpContext
,所以你能够检索它包含的任何可用的值,并将它们设置为IDiagnosticContext
所提供的属性。这些属性将做为附加属性添加到Serilog生成的结构化日志中。在下一篇文章中,我将展现如何将MVC特定的属性值添加到请求日志中。敬请期待吧!