39

如何使用Serilog.AspNetCore记录ASP.NET Core3.0的MVC属性

 4 years ago
source link: http://www.cnblogs.com/yilezhu/p/12243984.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

这是Serilog系列的第三篇文章。

  1. 第1部分-使用Serilog RequestLogging减少日志详细程度
  2. 第2部分-使用Serilog记录所选的终结点属性
  3. 第3部分-使用Serilog.AspNetCore记录MVC属性(本文)
  4. 第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的中间件不能直接访问。

在本文中,我将展示如何创建 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
}

无论你使用 AddControllersAddControllersWithViewsAddMvc ,或 AddMvcCore 的方式你都可以采用同样的方式来添加全局过滤器。

有了这个配置之后,如果你调用一个MVC控制器,你在Serilog的请求日志消息中会看到额外的数据( ActionNameActionId ,和 RouteDataValidationState )记录:

myQBF3Y.png!web

您可以在此处将所需的任何其他数据添加到日志中。只需注意记录参数值-切记不要记录敏感或个人身份信息!

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 RouteDataValidationState RazorPages的其他详细信息,则也需要在此处添加它。该 context 属性包含您可能需要的大多数属性,例如 ModelStateActionDescriptor

接下来,您需要在 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 属性:

YbMb6na.png!web

总结

默认情况下,当用Serilog的请求日志记录中间件替换ASP.NET Core基础结构中的日志记录时,您会丢失一些信息(与开发环境的默认配置相比)。在本文中,我将展示如何自定义Serilog, RequestLoggingOptions 以重新添加特定于MVC的其他属性。

要将与MVC相关的属性添加到Serilog请求日志中,请创建一个 IActionFilter 并使用 IDiagnosticContext.Set() 来添加属性。要将与Razor页面相关的属性添加到Serilog请求日志中,请在 IPageFilter 中使用 IDiagnosticContext 的相同方法创建和添加属性。

下一节让我们一起探讨下如何从Serilog请求记录中排除运行状况检查端点。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK