手机版

详细说明如何在ASP.NET核心应用程序中记录和查看日志

时间:2021-09-07 来源:互联网 编辑:宝哥软件园 浏览:

日志记录不仅对我们开发的应用程序非常重要,对ASP.NET核心框架功能也非常重要。我们知道ASP.NET核心使用一个可扩展的日志系统,该系统由三个核心对象组成:记录器、记录器工厂和记录器提供者。我们可以自定义LoggerFactory,通过简单的配置添加LoggerProvider。

I .配置记录器工厂

在上一节中,我们展示了一个显示ASP.NET核心网默认注册服务的示例。细心的读者会发现,显示的列表包含了为LoggerFactory提供的服务。如果默认的LoggerFactory服务不能满足我们的需求,我们可以配置任何需要的LoggerFactory,通过直接调用WebHostBuilder的UseLoggerFactory方法就可以实现对LoggerFactory的设置。

公共接口IWebHostBuilder { IWebHostBuilder UseLoggerFactory(ILoggerFactory logger factory);IWebHostBuilder配置日志记录(ActionILoggerFactory配置日志记录);但是日志配置更多的体现在添加了一个LoggerProvider,这可以通过调用WebHostBuilder的ConfigureLogging方法来完成.在上面的例子中,我们使用了下面的方法在LoggerFactory上注册了一个ConsoleLoggerProvider,这样我们就可以直接在宿主应用程序的扩展平台上看到记录的日志信息。

新的web主机生成器()。配置日志记录(工厂=工厂。addconsole()).由于LoggerFactory已经注册为服务,所以我们完全根据依赖注入来获取这个对象,并使用它来创建相应的Logger对象来写日志。如果我们需要在已定义的中间件中编写某种类型的日志,我们可以在Invoke方法中定义ILoggerFactory类型的参数,如下所示,并将它们注入到这个LoggerFactory中。

公共类FoobarMiddleware { private request delegate _ next;public FoobarMiddleware(request delegate next){ _ next=next;}公共异步任务调用(HttpContext上下文,ILoggerFactory logger factory){ ILoggerFoobarMiddleware logger=logger factory。createlogerfoobarmiddleware();伐木工。登录信息('.');wait _next(上下文);}}不仅我们开发的应用或中间件可以使用注册的LoggerFactory创建logger对象进行日志记录,而且ASP.NET Core管道本身在处理请求的过程中也会以同样的方式记录一些日志。例如,管道将在每个处理请求的开始和结束时写入两个信息级别的日志。现在让我们举一个简单的例子来看看这两个日志的内容是什么。

公共类Program { public static void Main(){ new WebHostBuilder()。配置日志记录(工厂=工厂。AddConsole())。UseKestrel()。UseStartupStartup()。构建()。run();} }公共类Startup {公共void Configure(IApplicationBuilder应用程序,ILoggerFactory logger factory){ app。运行(异步上下文={ loggerFactory。创建记录器(“应用”)。日志信息('测试的日志条目.');等待上下文。回应. WriteAsync('Hello world!');});}}上面显示的代码在两个地方与日志相关。首先是调用WebHostBuilder的ConfigureLogging方法,通过调用扩展方法AddConsole,向当前的LoggerFactory添加一个ConsoleProvider。另一个地方是,启动类的Configure方法注册的中间件会在执行过程中使用注入的LoggerFactory创建一个Logger对象,我们用后者写一个Information级别的日志。在我们运行程序后使用浏览器访问目标地址后,主机控制台上会出现如下图所示的三个日志。除了第二个日志是我们自己的代码写的,其他两个日志都是ASP.NET Core框架自己写的。第一个日志不仅包含请求的tarGET地址,还包含请求采用的协议(HTTP/1.1)和HTTP方法(GET),第三个日志反映了整个请求处理过程所花费的时间。

由于ASP.NET核心管道总是在由HttpApplication创建的执行上下文中处理请求,因此上下文的创建和回收可以被视为整个请求处理流程开始和结束的标志。至于上面两个写在处理请求开始和结束的日志,实际上是分别调用HostingApplication的CreateContext和DisposeContext方法时记录的。之所以可以在最后计算整个请求处理过程所花费的时间,是因为创建的Context对象保存了开始处理请求的时间戳,该时间戳对应于上下文结构的StartTimestamp属性。

公共类宿主应用程序ihttpapapplicationhostingapplication。上下文{公共结构上下文{公共HttpContext HttpContext { get设置;}公共IDisposable作用域{ get设置;} public long StartTimestamp { get设置;}}}其次,将当前请求作为日志范围

我们知道日志系统有一个概念叫做“日志范围”,目的是为多个相关的日志记录创建一个上下文范围,并为这个范围提供一个唯一的标识符,这个标识符将作为日志内容的一部分写入。当我们进行日志分析时,可以根据日志范围标识关联一组原本独立的日志。这个概念对于Web应用程序来说尤为重要,因为在很多情况下,我们做的日志分析都是针对某个请求的,这就需要我们明确区分记录的日志属于哪个请求。只有这样,我们才能针对同一请求提取所有日志,并进行综合分析,得出准确的结论。

根据上一个实例中写入的三个日志,它们不携带当前请求的标识信息。然而,这不是ASP.NET核心的问题,但是当我们调用日志工厂的扩展方法AddConsole来注册ConsoleLoggerProvider时,我们没有显式地打开对日志范围的支持。为了让注册的ConsoleLoggerProvider创建的Logger支持日志范围,我们只需要在以下列方式调用AddConsole方法时添加一个额外的参数(true)。

新的WebHostBuilder()。配置日志记录(工厂=工厂。AddConsole(true))。UseKestrel()。UseStartupStartup()。构建()。run();我们再次请求应用程序,并使用浏览器向目标地址发送两个请求,六个写入的日志将输出到控制台,如下图所示。与上面的输出结果不同,这次的日志输出包含了ID(Request Id),在同一个请求下记录的日志具有相同的ID。除了请求标识,记录的日志还携带请求路径。

日志范围携带的唯一标识当前请求的标识也可以看作当前HttpContext的唯一标识,对应于HttpContext的TranceIdentifier属性。对于DefaultHttpContext,这个属性的读写是通过一个名为httprequestidentifierdesign的特性来实现的。下面的代码提供了与此对象对应的接口ihttprerequesteidentifier design和默认实现类httprequestidentifierdesign的定义。

公共抽象类httpcontext {//省略其他成员公共抽象字符串跟踪标识符{ get设置;} }公共接口ihttprequestidentifier feature { string trace identifier { get;设置;} }公共类Httprequestidentifier feature ihttprequestidentifier feature { private string _ id;私有静态long _requestId=DateTime。UtcNow . Ticks私有静态不安全字符串GenerateRequestId(长id);公共字符串TraceIdentifier { get { return _id?(id=GenerateRequestId(互锁。增量(ref _ RequestID)));}设置{这个。_id=值;}}}通过httprequestidentifierfeature生成TraceIdentifier的逻辑非常简单。如上面的代码片段所示,它有一个静态长整型字段_requestId,其初始值是当前时间戳。对于特定的HttpRequestIdentifierFeature对象,其TraceIdentifier属性的默认值返回向该字段_requestId添加1后转换的字符串。具体的转换逻辑在GenerateRequestId方法中定义,会采用相应的算法将指定的整数转换成长度为13的字符串。

与开始请求处理的时间戳一样,创建的日志范围实际上保存在HostingApplication的Context对象中,该对象对应于上下文结构的Scope属性。当HostingApplication创建此上下文对象时,它将从当前的HttpContext中提取请求的ID和路径,创建此日志范围并将其分配给此属性。整个请求处理实际上是在这个日志范围内进行的,请求处理结束,当前的日志模型也被回收释放。

公共类宿主应用程序ihttpapapplicationhostingapplication。上下文{公共结构上下文{公共HttpContext HttpContext { get设置;}公共IDisposable作用域{ get设置;} public long StartTimestamp { get设置;}}}第三,记录异常日志

由于ASP.NET核心在处理请求的过程中导致的异常不会导致应用程序终止,考虑到安全性,抛出异常的细节不应该直接返回给客户端。因此,在很多情况下,我们甚至没有意识到应用程序是异常的,即使我们意识到了,我们也不知道异常的根本原因在哪里。在这种情况下,我们需要使用记录的日志进行纠错,因为ASP.NET核心在处理请求时遇到的异常将被记录在日志中。

例如,对于下面的程序,毫无疑问,任何请求的处理都会抛出一个DivideByZeroException的异常。如果我们使用浏览器访问站点地址,它只会得到一个状态为500的响应,并简单地提示服务器出现错误。就宿主程序而言,我们根本察觉不到任何异常的发生。

新的WebHostBuilder()。UseKestrel()。配置(app=app。Run(异步上下文={ int x=1;int y=0;等待上下文。Response.WriteAsync((x/y))。ToString());})) .构建()。run();在这种情况下,我们可以通过查看日志获得异常的详细信息,但是在此之前,我们必须为LoggerFactory注册相应的LoggerProvider。如果我们使用控制台应用程序作为主机,开发或调试的最简单方法是注册一个如下所示的ConsoleLoggerProvider,这样日志就可以直接写入主机程序的控制台。

新的WebHostBuilder()。配置日志记录(工厂=工厂。AddConsole (true))。UseKestrel()。配置(app=app。Run(异步上下文={ int x=1;int y=0;等待上下文。Response.WriteAsync((x/y))。ToString());})) .构建()。run();一旦为记录器工厂注册了这样一个ConsoleLoggerProvider,我们就可以直接在主机控制台上看到服务器端任何未处理异常的错误详细信息。下图显示了上述示例引发的DivideByZeroException异常的详细信息。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:详细说明如何在ASP.NET核心应用程序中记录和查看日志是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。