译者: Akini Xu
原文: Logging MVC properties with Serilog.AspNetCore
作者: Andrew Lock
此文是在ASP.NET Core 3.0中使用Serilog第3篇:
在本系列的上一篇中,我介绍了如何配置Serilog的RequestLogging中间件,来向Serilog的摘要日志中添加额外属性。 这些属性可以从HttpContext中获得,直接被中间件使用。
有一些属性(MVC特有的功能,例如Action名称,RazorPages处理程序名称或ModelValidationState等)仅在MVC上下文中可用,因此Serilog的中间件不能直接访问。
在本文中,我将介绍如何通过创建Action/Page的过滤器来记录这些属性,以方便中间件生成日志时使用。
Serilog的作者Nicholas Blumhardt在一篇文章中解决了这个问题。 他在示例中创建了一个attribute,并在actions/controllers中使用。 本文并没有采用这种方式,我想实现一种更通用的解决方案。 另外还可以查看他有关ASP.NET Core 3.0的Serilog相关文章
记录MVC中的额外信息
ASP.NET Core中有很多功能被封装在MVC“基础架构”之内。 目前,端点路由这个功能已经被迁移到.NET Core框架中实现了。 ASP.NET Core团队一直在努力将更多的MVC特有功能(例如模型绑定或操作结果)从MVC内部移出,然后迁移到核心框架中。 有关更多信息,请参见Ryan Nowak在NDC上对Houdini项目的讨论。
就目前情况而言,MVC内部仍然有一些信息,是不太容易从外部获取的。 当使用Serilog的RequestLogging中间件时,以下信息就不太容易获取:
- HandlerName (
OnGet) - ActionId (
1fbc88fa-42db-424f-b32b-c2d0994463f1) - ActionName (
MyController.SomeApiMethod (MyTestApp)) - RouteData (
{action = "SomeApiMethod", controller = "My", page = ""}) - ValidationState (
True/False)
在上一篇文章中,我介绍了如何使用RequestLogging中间件将额外附加信息写入Serilog的请求日志。 这仅适用于HttpContext中可访问的属性。 在这篇文章中,我将介绍如何在action filter中使用IDiagnosticContext将MVC特有的属性也添加到日志中。 还将介绍如何使用page filter添加RazorPages特有的属性(例如HandlerName)。
使用Action过滤器记录MVC特有属性
过滤器相当于MVC框架中的一个微型的中间件管道。MVC中有多种类型的过滤器,它们会在过滤器管道的不同位置运行(有关MVC过滤器更多详细信息,请参见此文章)。 在本文中,我们将使用最常见的过滤器之一,即Action filter。
Action过滤器会在MVCAction方法执行前和执行后运行。 这个过滤器可以访问到许多MVC特有的属性,例如将要执行的Action及执行它的参数。
下面的Action过滤器实现了IActionFilter接口。 当Action的方法被执行之前,会先调用此过滤器的OnActionExecuting方法,在此方法中获取MVC特有的属性,添加到IDiagnosticContext中。
public class SerilogLoggingActionFilter : IActionFilter |
在Startup.ConfigureServices()中注入MVC服务时,同时注入全局范围过滤器:
public void ConfigureServices(IServiceCollection services) |
无论您使用的是
AddControllers,AddControllersWithViews,AddMvc还是AddMvcCore,都可以以相同的方式注入全局过滤器。
完成此配置后,再次访问MVC的Controller,则会在Serilog请求日志消息中看到额外信息(ActionName,ActionId和RouteData,ValidationState):
您可以使用此方式,添加您所需的任何其他信息添加到日志中。 注意:不要记录敏感信息或个人身份信息!
Nicholas Blumhardt的文章中建议,Action过滤器从
ActionFilterAttribute派生的,方便其用作于controller和action。这样做意味着,必须使用IServiceProvider来获取单例的IDiagnosticContext对象。上面的方法改为使用构造函数注入,因此不能当Attribute使用。 另外,生命周期是scoped,非singleton,因此每次请求都会创建一个新实例。
如果要记录MVC过滤器管道中其他位置的相关属性,可以采用类似的方式实现其它过滤器,例如Resource filter、Result filter、Authorization filter。
使用Page过滤器记录RazorPages属性
上面的IActionFilter只能在MVC controller和API controller上运行,但不能在RazorPages上运行。 如果要记录为指定Razor页面对应的HandlerName,则需要创建一个自定义IPageFilter。
Page filters类似于Action filters,但只仅适用于Razor Pages 。 下面的示例从PageHandlerSelectedContext获取HandlerName。最后调用IDiagnosticContext .Set()来记录属性。
public class SerilogLoggingPageFilter : IPageFilter |
请注意,之前编写的IActionFilter不会在Razor Pages上运行,因此,如果也想为RazorPages记录诸如RouteData或ValidationState之类的其他详细信息,那么也需要在此处添加那些代码。 context属性包含大多数需要的属性,例如ModelState和ActionDescriptor。
接下来,您需要在Startup.ConfigureServices()方法中注册Page filters:
public void ConfigureServices(IServiceCollection services) |
添加过滤器后,对Razor Pages的请求额外属性将会添加到Serilog请求日志中。 请参见下图中的RazorPageHandler属性:
总结
默认情况下,当用Serilog的请求日志记录中间件替换ASP.NET Core基础日志组件时,会丢失一些信息(与开发环境的默认配置相比)。 在本文中,我介绍了如何自定义Serilog的RequestLoggingOptions来添加MVC特有的其他属性。
需要添加MVC相关的属性到Serilog请求日志中,创建IActionFilter并使用IDiagnosticContext.Set()添加属性。
需要添加Razor页面相关的属性添加到Serilog请求日志中,创建IPageFilter并使用IDiagnosticContext添加属性。




