内容简介:这是Serilog系列的第三篇文章。作者:依乐祝译文地址:
这是Serilog系列的第三篇文章。
- 第1部分-使用Serilog RequestLogging减少日志详细程度
- 第2部分-使用Serilog记录所选的终结点属性
- 第3部分-使用Serilog.AspNetCore记录MVC属性(本文)
- 第4部分-从Serilog请求记录中排除运行状况检查端点
作者:依乐祝
译文地址: https://www.cnblogs.com/yilezhu/p/12243984.html
在我上篇文章中,我描述了如何配置Serilog的RequestLogging中间件以向Serilog的请求日志摘要中添加其他属性(例如请求主机名或选定的端点名称)。这些属性都在 HttpContext
中可用,因此可以由中间件本身直接添加。
其他属性,例如MVC特定的功能,像操作方法ID,RazorPages处理程序名称或ModelValidationState, 仅 在MVC上下文中可用,因此Serilog的中间件不能直接访问。
在本文中,我将展示如何创建 action/page
过滤器来为您记录这些属性,以便中间件可以在后续创建日志时访问。
Serilog的创建者Nicholas Blumhardt之前已经解决了这个话题 。解决方案非常相似,尽管他在他的示例中创建了一个特性,您可以使用该特性来装饰 actions/controllers 。我在本文中跳过了这种方法,并要求将其全局应用,我希望这将是常见的解决方案。
记录来自MVC的其他信息
就目前而言,ASP.NET Core中的一个特征是许多行为被MVC“基础结构”锁定在了MVC框架内部来实现。端点路由是采用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过滤器在执行MVC操作方法之前和之后运行。他们可以访问许多MVC属性的值,例如正在执行的Action及其将被调用的参数。
下面的Action过滤器直接实现 IActionFilter
。该 OnActionExecuting
方法在调用action方法之前被调用,并将额外的MVC特定属性添加到通过构造函数传入的 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 interface public 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的请求日志消息中会看到额外的数据( ActionName
, ActionId
,和 RouteData
, ValidationState
)记录:
您可以在此处将所需的任何其他数据添加到日志中。只需注意记录参数值-切记不要记录敏感或个人身份信息!
Nicholas Blumhardt在他的帖子中建议 的Action过滤器是从 ActionFilterAttribute
派生的,因此可以将其直接用作控制器和Action的特性。不幸的是,这意味着您必须使用服务定位来从每个请求的 HttpContext
中检索单例的 IDiagnosticContext
。我的方法可以改用构造函数注入,但是不建议将其用作属性,因此必须如上所述全局使用。而且,MVC将在我的实现中使用作用域生存期,而不是单例,因此它会在每个请求中创建一个新实例。
如果要记录其他集中MVC过滤器中的值,则可以以相同的方式实现其他过滤器,例如资源过滤器,结果过滤器或授权过滤器。
使用自定义page过滤器记录RazorPages属性
上面实现的 IActionFilter
过滤器在MVC和API控制器上能够正常运行,但它 不会 对RazorPages起作用。如果要为选择的给定Razor页面记录HandlerName,则需要创建一个自定义的 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 interface public 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
或 ValidationState
RazorPages的其他详细信息,则也需要在此处添加它。该 context
属性包含您可能需要的大多数属性,例如 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页面”的请求现在可以看到添加的附加属性, IDiagnosticContext
这些属性将添加到Serilog请求日志中。请参见下图中的 RazorPageHandler
属性:
总结
默认情况下,当用Serilog的请求日志记录中间件替换ASP.NET Core基础结构中的日志记录时,您会丢失一些信息(与开发环境的默认配置相比)。在本文中,我将展示如何自定义Serilog, RequestLoggingOptions
以重新添加特定于MVC的其他属性。
要将与MVC相关的属性添加到Serilog请求日志中,请创建一个 IActionFilter
并使用 IDiagnosticContext.Set()
来添加属性。要将与Razor页面相关的属性添加到Serilog请求日志中,请在 IPageFilter
中使用 IDiagnosticContext
的相同方法创建和添加属性。
下一节让我们一起探讨下如何从Serilog请求记录中排除运行状况检查端点。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Serilog高级玩法之用Serilog记录所选终结点附加属性
- CSS 属性篇(七):Display属性
- JavaScript对象之数据属性与访问器属性
- Logback file属性 与 fileNamePattern属性的关系
- 浅谈Spring Boot 属性配置和自定义属性配置
- python – Django属性错误. ‘module’对象没有属性’rindex’
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。