ASP.NET Core 源码学习之Logging[1]:Introduction

在ASP.NET 4.X中,我们通常使用 log4net, NLog 等来记录日志,但是当我们引用的一些第三方类库使用不同的日志框架时,就比较混乱了。而在 ASP.Net Core 中内置了日志系统,并提供了一个统一的日志接口,ASP.Net Core 系统以及其它第三方类库等都使用这个日志接口来记录日志,而不关注日志的具体实现,这样便可以在我们的应用程序中进行统一的配置,并能很好的与第三方日志框架集成。

注册日志服务

ASP.NET Core 全部使用依赖注入,更好的规范我们的代码。想要使用日志系统,首先要进行注册和配置:

public void ConfigureServices(IServiceCollection services)  {services.AddLogging(builder =>{builder.AddConfiguration(loggingConfiguration.GetSection("Logging")).AddFilter("Microsoft", LogLevel.Warning).AddConsole();});
}

如上,通过 AddLogging ,将日志系统注册到了 DI 系统中,而 AddConfiguration 是对日志系统的全局配置, AddFilter 则是对日志过滤器的一些配置,最后 AddConsole 添加了一个 Console 的日志提供者(将日志输出到控制台)。

记录日志

在我们需要记录日志的时候,只需要通过构造函数注入ILogger<T>就可以了:

public class TodoController : Controller{    private readonly ITodoRepository _todoRepository;    private readonly ILogger _logger;    public TodoController(ITodoRepository todoRepository, ILogger<TodoController> logger)    {_todoRepository = todoRepository;_logger = logger;}[HttpGet]    public IActionResult GetById(string id)    {_logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);        var item = _todoRepository.Find(id);        if (item == null){_logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);            return NotFound();}        return new ObjectResult(item);}  
}

ILogger<T> 中的 T 表示日记的类别,在我们查看日志时,非常有用,在本文后面会讲。

日志输出示例

使用上面的示例代码,当我们通过控制台来运行时,访问 http://localhost:5000/api/todo/0 将会看到如下的日志输出:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]Request starting HTTP/1.1 GET http://localhost:5000/api/todo/invalididinfo: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]Executing action method TodoApi.Controllers.TodoController.GetById (TodoApi) with arguments (invalidid) - ModelState is Validinfo: TodoApi.Controllers.TodoController[1002]Getting item invalididwarn: TodoApi.Controllers.TodoController[4000]GetById(invalidid) NOT FOUNDinfo: Microsoft.AspNetCore.Mvc.StatusCodeResult[1]Executing HttpStatusCodeResult, setting HTTP status code 404info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]Executed action TodoApi.Controllers.TodoController.GetById (TodoApi) in 243.2636msinfo: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]Request finished in 628.9188ms 404

如果我们访问 http://localhost:55070/api/todo/0 ,将会看到:

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:55070/api/todo/invalidid
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method TodoApi.Controllers.TodoController.GetById (TodoApi) with arguments (invalidid) - ModelState is Valid
TodoApi.Controllers.TodoController:Information: Getting item invalidid
TodoApi.Controllers.TodoController:Warning: GetById(invalidid) NOT FOUND
Microsoft.AspNetCore.Mvc.StatusCodeResult:Information: Executing HttpStatusCodeResult, setting HTTP status code 404Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action TodoApi.Controllers.TodoController.GetById (TodoApi) in 12.5003ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 19.0913ms 404

通过这个示例,可以看到我们记录到了 ASP.NET Core 框架自身的日志,这也是统一的日志框架才能实现的功能。

日志类别

我们创建的每一个日志器都指定了一个类别。它可以是任意的字符串,但是约定使用写入类的完整限定名,如:“TodoApi.Controllers.TodoController”。如果要显式的指定日志的种类,则可以使用 ILoggerFactory 中的 CreateLogger 方法:

public class TodoController : Controller{    

 private readonly ILogger _logger;  
 public TodoController(ILoggerFactory logger)    {_logger = logger.CreateLogger("TodoApi.Controllers.TodoController");} }

不过,大多数时候,我们还是使用 ILogger<T>,更加方便:

public class TodoController : Controller{   

  private readonly ILogger _logger;  
  public TodoController(ILogger<TodoController> logger)    {_logger = logger;} }

这等效于使用 T 类型的完整限定名来调用 CreateLogger 方法。

日志级别

在我们记录日志时,需要指定日志的级别,这对我们过滤日志非常有用,比如在测试环境中,我们希望提供非常的详细的日志信息,包括一些敏感信息等,但是在生产环境中,我们希望只记录严重的错误,这时候只需要简单的通过 AddFilter 对日志的过滤级别配置一下就行了。

ASP.NET Core Logging 系统提供了六个日志级别,通过增加重要性或严重程度排序如下:

  • Trace 用于记录最详细的日志消息,通常仅用于开发阶段调试问题。这些消息可能包含敏感的应用程序数据,因此不应该用于生产环境。默认应禁用。

  • Debug 这种消息在开发阶段短期内比较有用。它们包含一些可能会对调试有所助益、但没有长期价值的信息。默认情况下这是最详细的日志。

  • Information 这种消息被用于跟踪应用程序的一般流程。与 Verbose 级别的消息相反,这些日志应该有一定的长期价值。

  • Warning 当应用程序出现错误或其它不会导致程序停止的流程异常或意外事件时使用警告级别,以供日后调查。在一个通用的地方处理警告级别的异常。

  • Error 当应用程序由于某些故障停止工作则需要记录错误日志。这些消息应该指明当前活动或操作(比如当前的 HTTP 请求),而不是应用程序范围的故障。

  • Critical 当应用程序或系统崩溃、遇到灾难性故障,需要立即被关注时,应当记录关键级别的日志。如数据丢失、磁盘空间不够等。

日志事件ID

每次写日志的时候,我们可以指定一个 event ID

public class LoggingEvents{   
    public const int GET_ITEM = 1002;
    public const int GET_ITEM_NOTFOUND = 4000; }
  
public IActionResult GetById(string id){_logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);    var item = _todoRepository.Find(id);  
  if (item == null){_logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);      
   return NotFound();}  
    return new ObjectResult(item); }

event ID 是一个整数,它可以将一组日志事件关联到一起。与日志类别类似,但是更加细化。而它的输出取决于日志提供者,Console 提供者输出格式如下,在日志类别后面,并用一对中括号包裹着:

info: TodoApi.Controllers.TodoController[1002]Getting item invalididwarn: TodoApi.Controllers.TodoController[4000]GetById(invalidid) NOT FOUND

日志格式化字符串

每次记录日志时,都会提供一条文本消息,而在这个消息字符串中,我们可以使用命名占位符:

public IActionResult GetById(string id){_logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);    var item = _todoRepository.Find(id);   
 if (item == null){_logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);  
      return NotFound();}  
       return new ObjectResult(item); }

但是占位符的顺序决定了使用哪个参数,而不是它的名字,如下示例:

string p1 = "parm1";string p2 = "parm2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);

输出结果为:

Parameter values: parm1, parm2

那这样做有什么意义呢?

日志框架使用这种消息格式化方式,使日志提供者能够实现 语义化日志,也称结构化日志。因为参数本身被传递到日志系统中,而不仅仅是格式化的字符串,因此日志提供者可以将参数的值作为字段存储单独的存储。比如:如果使用 Azure Table Storage,我们可以使用如下方法来记录日志:

_logger.LogInformation("Getting item {ID} at {RequestTime}", id, DateTime.Now);

每一个 Azure Table 都可以有 ID 和 RequestTime 属性,这将简化对日志数据的查询,你可以查找指定 RequestTime 范围内的所有日志,而不必花费解析文本消息的开销。

过滤器

过滤器可以让你根据日志的级别和类别来选择是输出,还是忽略。我们可以为不同的日志提供者指定不同的过滤器,如下代码所示,让 Console 提供者忽略低于 warning 级别的日志,而 Debug 提供者则忽略 TodoApi 类别的日志。

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory){loggerFactory.AddConsole(LogLevel.Warning).AddDebug((category, logLevel) => (category.Contains("TodoApi") && logLevel >= LogLevel.Trace));
}

而我们还可以指定全局过滤器,作用于所有的日志提供者,如下示例,我们对于以 "Microsoft" 和 "System" 开头的日志类别忽略掉低于 Warning 级别的日志:

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory){loggerFactory.AddFilter("Microsoft", LogLevel.Warning).AddFilter("System", LogLevel.Warning).AddFilter("SampleApp.Program", LogLevel.Debug).AddDebug();
}

作用域

我们可以将一组逻辑操作放在一个有序的 Scope 中,将 Scope 的标识附加到范围内的所有日志中。例如,我们可以在处理事务的时候,使事务内的每一个操作日志都包含这个事务的ID。

使用ILgger.BeginScope<TState> 方法创建一个 Scope,并返回一个 IDisposable 类型,当我们 Dispose的时候,这个 Scope 也就结束了,非常适合于使用 using 的方式:

public IActionResult GetById(string id){TodoItem item;    using (_logger.BeginScope("Message attached to logs created in the using block")){_logger.LogInformation(LoggingEvents.GET_ITEM, "Getting item {ID}", id);item = _todoRepository.Find(id);        if (item == null){_logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND, "GetById({ID}) NOT FOUND", id);            return NotFound();}}    return new ObjectResult(item);
}

每一个日志将包括 Scope 的信息:

info: TodoApi.Controllers.TodoController[1002]=> RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using blockGetting item 0
warn: TodoApi.Controllers.TodoController[4000]=> RequestId:0HKV9C49II9CK RequestPath:/api/todo/0 => TodoApi.Controllers.TodoController.GetById (TodoApi) => Message attached to logs created in the using blockGetById(0) NOT FOUND

总结

ASP.NET Core 提供了统一的日志框架,能方便地通过 Startup 类进行配置,灵活的集成第三方日志框架,并使用依赖注入的方式在应用程序中使用。本文整体的概述了一下 Logging 系统,在下一章中,会来分析一下 Logging 中配置的源码。

参考微软官方文档:Introduction to Logging in ASP.NET Core

相关文章: 

  • ASP.NET Core 源码学习之 Options[1]:Configure

  • ASP.NET Core 源码学习之 Options[2]:IOptions

  • ASP.NET Core 源码学习之 Options[3]:IOptionsSnapshot

  • ASP.NET Core 源码学习之 Options[4]:IOptionsMonitor

  • ASP.NET Core MVC 源码学习:详解 Action 的匹配

  • asp.net core源码飘香:从Hosting开始

  • asp.net core源码飘香:Configuration组件

  • asp.net core源码飘香:Options组件

  • asp.net core源码飘香:Logging组件

原文地址:http://www.cnblogs.com/RainingNight/p/asp-net-core-logging-introduction.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全国教学交流研讨会“教学为本”主题总结

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。最近&#xff0c;我的个人站上线啦&#xff0c;大家可以直接在浏览器的地址栏中输入&#xff1a;穆雄雄.com&#xff0c;轻轻敲击回车&#xff0c;即可直接进入……

JFreeChart(六)之3D饼图/条形图

转载自 JFreeChart 3D饼图/条形图 三维/3D图表是那些显示在一个三维格式。可以使用这些图表来提供更好的显示效果和清晰的信息。三维/3D饼图是饼图另外一个不错的3D效果。 3D效果可以通过添加一些额外的代码来实现&#xff0c;它会创建一个饼图3D效果。 3D饼图 请看下面的…

P2598-狼和羊的故事【最大流,最小割】

正题 评测记录&#xff1a; https://www.luogu.org/recordnew/lists?uid52918&pidP2598 大意 有n*m的矩阵&#xff0c;里面有羊和狼(也有可能是空)&#xff0c;可以在两个格子之间围上篱笆让两个格子不能互相到达&#xff0c;要求狼的格子不能和羊的格子在同一个联通块…

.NET Core 2.0 正式发布信息汇总

万众瞩目的.NET Core 2.0终于发布了&#xff0c;原定于9.19的dotnetconf大会的发布时间大大提前了1个月&#xff0c;.NET Core 2.0/.NET Standard 2.0的正式发布是.NET 开源跨平台的一个重大里程碑&#xff0c; 可以激活庞大的10几年以来各大公司和社区.NET 平台上的投资&#…

JFreeChart(七)之气泡图表​​​​​​​

转载自 JFreeChart气泡图表 本章演示如何使用JFreeChart从一个给定的业务数据创建气泡图表。使用气泡图显示在三维方式的信息。气泡绘制在其中(x&#xff0c;y)坐标相交的地方。气泡的大小被认为是范围或X和Y轴的数量。 业务数据 考虑不同的人的年龄&#xff0c;体重和工作…

家校共建,用心教学

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。最近&#xff0c;我的个人站上线啦&#xff0c;大家可以直接在浏览器的地址栏中输入&#xff1a;穆雄雄.com&#xff0c;轻轻敲击回车&#xff0c;即可直接进入……

2018/7/6-纪中某C组题【jzoj1192,jzoj1397,jzoj1736】

前言 全体爆零&#xff0c;十分开心 正题 T1&#xff1a;矩阵 大意 就是N个矩阵&#xff0c;然后进行矩阵乘法(n∗mn∗m和m∗pm∗p的矩阵相乘就会变成n∗pn∗p的矩阵并且运算次数是n∗m∗pn∗m∗p)&#xff0c;然后求最小乘法运算次数。 考试时 一直以为会是图论&#xff…

ASP.NET Core - Razor页面之Handlers处理方法

简介 在前一篇文章中&#xff0c;我们讨论了Razor页面。今天我们来谈谈处理方法&#xff08;Handlers&#xff09;。我们知道可以将代码和模型放在 .cshtml 文件里面或与 .cshtml 匹配的 .cshtml.cs 文件中。Razor页面处理程序或处理方法将用户请求匹配到我们的方法&#xff1…

JFreeChart(八)之时序图

转载自 JFreeChart时序图 时序图表显示的数据点在相等的时间间隔序列变化。本章演示了如何从一个给定的业务数据使用JFreeChart&#xff0c;建立时序图。 业务数据 让我们考虑通过使用标准 Java API 的 Math.random()产生的各种随机数。我们使用这些数字产生一个时间序列图…

立德树人

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。最近&#xff0c;我的个人站上线啦&#xff0c;大家可以直接在浏览器的地址栏中输入&#xff1a;穆雄雄.com&#xff0c;轻轻敲击回车&#xff0c;即可直接进入……

.NET Standard 2.0 特性介绍和使用指南

前言 早上起来.NET社区沸腾了&#xff0c;期待已久的.NET Core 2.0终于发布&#xff01;根据个人经验&#xff0c;微软的产品一般在2.0时会趋于成熟&#xff0c;所以一个新的.Net开发时代已经来临&#xff01;未来属于.NET Core。 对于.NET Core 2.0的发布介绍&#xff0c;围绕…

2018/7/7-纪中某C组题【jzoj1494,jzoj1495,jzoj1496,jzoj1497】

前言 290卡成145&#xff0c;十分开心。 正题 T1&#xff1a;密码 大意 N个数乘起来 考试时 看起来十分简单的高精乘单精 解题思路 10241024其实是10241024高精乘高精了解一下&#xff0c;30分QAQ 代码(高精乘高精我就不解释了吧) #include<cstdio> #include<…

加油四班!加油佟穆!我们的征途是星辰大海!!!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】首先&#xff0c;感谢佟老师与范老师&#xff0c;在我不在的时候&#xff0c;三班的就业和四班的学习都落在了两位老师的肩头&#xff0c;其次&#xff0c;还需要特别感谢冯老师&#xff0c;能抽时间…

JFreeChart(一)之架构

转载自 JFreeChart架构 本章介绍给大家介绍 JFreeChart 不同类中如何交互的概念, JFreeChart基本类层次和应用水平的架构在基于Java应用程序如何工作的。 类层次架构 类层次架构解释了如何把不同阶层的相互库交互&#xff0c;以创建不同类型的图表。 以下是在上述框图中使用…

体验 PHP under .NET Core

昨天在 The week in .NET 中发现 Scott Hanselman 的这篇博文 Peachpie - Open Source PHP Compiler to .NET and WordPress under ASP.NET Core&#xff0c;知道了 Peachpie PHP 编译器加入了 .NET 基金会&#xff0c;借助 Peachpie &#xff0c;.NET Core 已经支持 PHP 。 今…

上学的你,是不是最怕老师给家长打电话……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号&#xff1a;雄雄的小课堂。今天&#xff0c;做了个重要的工作&#xff0c;趁着五一这个假期&#xff0c;准备和每个家长都通一次话&#xff0c;将学生在学习情况给家长说明一下&#xff0c;站在我的角度&#xff0c;也从…

2018/7/8-纪中某C组题【jzoj1619,jzoj1620,jzoj1621,jzoj1622】

前言 分数250250&#xff0c;十分开心 正题 T1&#xff1a;音乐节拍 洛谷题目链接&#xff1a;https://www.luogu.org/problemnew/show/P2969 大意 有n段音乐&#xff0c;每段音乐持续时间不同&#xff0c;q个询问求一个时间点再放那首歌 考试时 开始时发现询问的时间点不…

IDEA一定要改的8条配置

转载自 IDEA一定要改的8条配置 引言 坦白说&#xff0c;我很少写这种操作类型的文章。因为这种文章没啥新意&#xff0c;大家操作步骤肯定是一样的。然而&#xff0c;我答应了我的同事小阳&#xff0c;给她出一篇&#xff01;毕竟人家打算从Eclipse转IDEA了&#xff0c;于是…

.NET Core 2.0使用NLog

最近研究了一下NLog的使用方式&#xff0c;简单的入了一下门。 实现的功能&#xff0c;对于不同的日志&#xff0c;进行不同的记录&#xff0c;分别有系统运行日志&#xff0c;和个人在程序中写的异常日志。发布之后放在了IIS上。进行查看日志的信息 参考了两篇博客。 1.ht…

计划得一步一步实施,题库首先是第一步!

大家好&#xff0c;我是雄雄&#xff0c;好久没见了哈&#xff0c;欢迎关注公众号&#xff1a;雄雄的小课堂。今天上午没有讲课&#xff0c;听写以及把假期作业整理了下&#xff0c;部分学生的假期作业偷工减料&#xff0c;也都让让让他们挨个补上了。上午将对班级后期的整个计…