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

  1. 第1部分-如何利用Serilog的RequestLogging来精简ASP.NET Core的日志输出

  2. 第2部分-Serilog高级玩法之用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(TrueFalse

在上一篇文章中我展示了如何使用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 interfacepublic 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)记录:

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

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 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 RouteDataValidationStateRazorPages的其他详细信息,则也需要在此处添加它。该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属性:

总结

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

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

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

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

  1. ASP.NET 2.0 – 善用DataSourceMode属性 (转自章立民CnBlogs)

    ASP.NET 2.0 – 善用DataSourceMode属性 SqlDataSource控件的DataSourceMode属性决定所提取的数据要如何维护. DataSourceMode属性的默认值 ...

  2. asp.net core3.0 mvc 用 autofac

    好久没有写文章了,最近在用.net core3.0,一些开发中问题顺便记录: 1.首先nuget引入 Autofac Autofac.Extensions.DependencyInjection 2. ...

  3. ASP.NET 2.0 – 善用DataSourceMode属性

    SqlDataSource控件的DataSourceMode属性决定所提取的数据要如何维护.<?xml:namespace prefix = o /> DataSourceMode属性的默 ...

  4. asp.net 2.0中一次性更新所有GRIDVIEW的记录

    在asp.net 2.0中,gridview控件是十分不错的控件.有的时候,可能一个GRIDVIEW控件中 的各行都是文本框,如何一次性更新所有修改过的记录呢?有两种方法,一种是使用sqldataso ...

  5. asp.net 2.0中用GRIDVIEW插入新记录

    出处:www.knowsky.com 作者:www.knowsky.com <script language=JavaScript src="/ad/ad.js">&l ...

  6. Enterprise Library 2.0 技巧(3):记录ASP.NET站点中未处理的异常

    这篇文章不能算是Enterprise Library 2.0的一个技巧,只是Logging Application Block的一个简单应用而已,在这里我们使用Logging Application ...

  7. 艾伟:【翻译】使用ASP.NET 2.0记录错误

    原文:http://www.dotnetcurry.com/ShowArticle.aspx?ID=94&AspxAutoDetectCookieSupport=1 使用ASP.NET 2.0 ...

  8. EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录

    前言 本文主要是讲解EF Core3.0+ 通过拦截器实现读写分离与SQL日志记录 注意拦截器只有EF Core3.0+ 支持,2.1请考虑上下文工厂的形式实现. 说点题外话.. 一晃又大半年没更新技 ...

  9. Log4Net异常日志记录在asp.net mvc3.0的应用

    前言 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是简单的介绍如何在Visual ...

最新文章

  1. 2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J Beautiful Numbers
  2. python文档生成工具 sphinx 简介
  3. Html:upload
  4. 深度解析企业级存储解决方案
  5. 独家对话阿里云函数计算负责人不瞋:你所不知道的 Serverless
  6. linux各种查看端口号
  7. 【laravel5.4 + TP5.0】hasOne和belongsTo的区别
  8. linux识别新加存储盘,Linux下新加磁盘
  9. Android下文件的压缩和解压(Zip格式)
  10. maven 关于使用 snapshot 的坑
  11. java 消费者 生产者 队列_用Java写一个生产者-消费者队列
  12. Linux 用inotify监听文件和目录
  13. POJ P1185 炮兵阵地 【状压dp】
  14. Flutter之Stack
  15. VS F5自动编译 F5不自动编译
  16. GPS同步时钟(NTP时钟服务器)常见故障解决与价格差异分析
  17. excel打不开_2016EXCEL表格打不开,提示格式与文件扩展名指定的格式不一致,这么做!...
  18. 显微镜C接口_壁虎支架、AI相机、手机镜头、便携显微镜,十一旅行有它们更精彩...
  19. windows应用程序与控制台应用程序的区别
  20. rpm包管理器常见用法

热门文章

  1. Windows按名称排序问题
  2. 60佳优秀的 Photoshop 网页制作教程【下篇】
  3. word 替换 增加引号_如何在Word 2013文档中替换部分(不是全部)智能引号
  4. 简单的单臂路由的配置实验 (思科)
  5. vue vue-router vuex element-ui axios 写一个代理平台的学习笔记(十一)构思商品页面...
  6. SSIS 执行变量中的脚步输出列顺序与SQL查询列顺序不同
  7. CMD、AMD、commonJs 规范的写法
  8. Word打不开,如何修复word文档?
  9. 如何扩展开发团队(转)
  10. 深入理解Magento-第十章-数据操作数据收集器