zoukankan      html  css  js  c++  java
  • asp.net core 3.1 日志记录 Logging

    Ilogger:包括实际执行记录日志操作的方法。
    IloggerProvider:用于创建 ILogger 对象。
    IloggerFactory:通过 ILoggerProvider 对象创建 ILogger 对象。

    ILogger接口

    要记录日志,需要使用 ILogger 接口

    public interface ILogger
    {
    	//开始逻辑操作范围。
    	IDisposable BeginScope<TState>(TState state);
    	//检查是否已启用给定 logLevel。
    	bool IsEnabled(LogLevel logLevel);
    	//写入日志项。
    	void Log<TState> (Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId 		eventId, TState state, Exception exception, Func<TState,Exception,string> formatter);
    }
    

    日志级别

    Log 方法的第一个参数指明了这条信息的级别,日志级别即其重要程度。ASP.NET Core 日志系统定义了 6 个级别

    LogLevel “值” 方法 描述
    Trace 0 LogTrace 包含最详细的消息。 这些消息可能包含敏感的应用数据。 这些消息默认情况下处于禁用状态,并且不应在生产中启用。
    调试 1 LogDebug 用于调试和开发。 由于量大,请在生产中小心使用。
    信息 2 LogInformation 跟踪应用的常规流。 可能具有长期值。
    警告 3 LogWarning 对于异常事件或意外事件。 通常包括不会导致应用失败的错误或情况。
    错误 4 LogError 表示无法处理的错误和异常。 这些消息表示当前操作或请求失败,而不是整个应用失败。
    严重 5 LogCritical 需要立即关注的失败。 例如数据丢失、磁盘空间不足。
    6 指定日志记录类别不应写入任何消息。

    ​ 除了指定日志级别以外,还需要指定 EventId、一个返回值类型为字符串的委托,该委托的意义在于根据指定的状态以及异常返回要输出的日志信息。从上面的代码中可以看出,直接使用 Log 方法来记录日志会非常麻烦。为此 ILogger 接口提供了若干个扩展方法,用来更方便地记录指定级别的日志,它们包括 LogTrace、LogDebug、LogInformation、LogWarning、LogError 和 LogCritical,这几个方法分别对应上面所提到的各个级别。因此,上面的代码可以改写为:

    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;
    
        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }
        
        public void OnGet()
        {
            _logger.LogInformation("GET Pages.PrivacyModel called.");
        }
    }
    

    在Startup记录日志

    ​ 当 ASP.NET Core 应用程序运行时,日志组件会被添加到其依赖注入容器中,因此只要在合适的位置将 ILogger 对象注入进来,即可使用它来记录日志。

    public class Startup
    {
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
        {
                    app.Run(async (context) =>
                    {
                        logger.LogInformation("这是一条测试日志");
                        await context.Response.WriteAsync("Hello, world");
                    });
        }
    }
    

    在 Startup 类的 Configure 方法中,通过方法注入将ILogger<Startup> 作为该方法的参数注入进来

    ​ ILogger 接口有一个派生接口 ILogger<out TCategoryName>,其中泛型类型 TCategoryName 表示日志类别名称,它可以是任何类型,通常情况下,它的值应为当前所在类,如上面的 Startup 类。当注入 ILogger 时,必须为其指定泛型类型。

    日志事件 ID

    ​ 在日志的输出结果中,日志类别后有一个用中括号括起来的数字,该数字为事件标识符(Event Id) ,它的值是一个数字,默认值为 0。合理地使用这个数字能够帮助开发者对日志进一步分类,比如,某种操作的 Id 是1000,另一类操作的 Id 是 1002。注意,Event Id 的显示格式由 Provider定义,上述显示形式是由 ConsoleProvider(即控制台日志提供程序)定义的;在其他 Provider 中则不然,例如,DebugProvider 不显示 Event Id。要设置 Event Id,我们只要使用 LogInformation 方法的另一个重载形式即可。

    每个日志都可指定一个事件 ID 。 示例应用使用 MyLogEvents 类来定义事件 ID:

    public class MyLogEvents
    {
        public const int GenerateItems = 1000;
        public const int ListItems     = 1001;
        public const int GetItem       = 1002;
        public const int InsertItem    = 1003;
        public const int UpdateItem    = 1004;
        public const int DeleteItem    = 1005;
    
        public const int TestItem      = 3000;
    
        public const int GetItemNotFound    = 4000;
        public const int UpdateItemNotFound = 4001;
    }
    
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        _logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
    
        var todoItem = await _context.TodoItems.FindAsync(id);
    
        if (todoItem == null)
        {
            _logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
            return NotFound();
        }
    
        return ItemToDTO(todoItem);
    }
    

    ​ 事件 ID 与一组事件相关联。 例如,与在页面上显示项列表相关的所有日志可能是 1001。

    ​ 日志记录提供程序可将事件 ID 存储在 ID 字段中,存储在日志记录消息中,或者不进行存储。 调试提供程序不显示事件 ID。 控制台提供程序在类别后的括号中显示事件 ID:

    info: TodoApi.Controllers.TodoItemsController[1002]
          Getting item 1
    warn: TodoApi.Controllers.TodoItemsController[4000]
          Get(1) NOT FOUND
    

    一些日志记录提供程序将事件 ID 存储在一个字段中,该字段允许对 ID 进行筛选。

    内置日志记录提供程序

    public static IWebHostBuilder CreateDefaultBuilder(string[] args)
    {
    	var builder = new WebHostBuilder();
    	…
        builder.ConfigureLogging((hostingContext, logging) =>
        {
            logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
            logging.AddConsole();
            logging.AddDebug();
            logging.AddEventSourceLogger();
        })
    	…
    }
    

    ​ CreateDefaultBuilder 方法默认添加了 3 个日志提供程序,如果不需要默认所添加的这些日志提供程序,可以调用 ILoggerProvider 接口的 ClearProviders 方法,然后再添加所需要的日志提供程序。

    • 控制台
      向控制台窗口输出日志
    • 调试
      向开发环境(IDE)的调试窗口输出日志,它会调用System.Diagnostics.Debug 类的 WriteLine 方法向外输出。
    • EventSource
      向事件跟踪器输出日志。
    • EventLog
      向 Window Event Log 输出日志,仅支持 Windows 操作系统。
    • AzureAppServicesFile 和 AzureAppServicesBlob
      仅在 Azure 中使用,当应用程序部署到 Azure Web服务中后, Azure App Service 日志提供程序自动会添加进来。
    • ApplicationInsights
      提供程序包将日志写入 Azure Application Insights。 Application Insights 是一项服务,可监视 Web 应用并提供用于查询和分析遥测数据的工具。 如果使用此提供程序,则可以使用 Application Insights 工具来查询和分析日志。

    ​ 与 ILoggingBuilder 一样,ILoggerFactory 在添加 ASP.NET Core 内置的日志提供程序时,也可以使用 AddConsole 和 AddDebug 等扩展方法来添加日志提供程序。

    第三方日志记录提供程序

    适用于 ASP.NET Core 的第三方日志记录框架:

    某些第三方框架可以执行语义日志记录(又称结构化日志记录)

    使用第三方框架类似于使用以下内置提供程序之一:

    1. 将 NuGet 包添加到你的项目。
    2. 调用日志记录框架提供的 ILoggerFactory 扩展方法。

    有关详细信息,请参阅各提供程序的相关文档。 Microsoft 不支持第三方日志记录提供程序。

    ILoggerFactory

    ILoggerFactory 接口用于创建 ILogger 类型的对象。

    public interface ILoggerFactory : IDisposable
    {
        //将 ILoggerProvider 添加到日志记录系统。
    	void AddProvider(ILoggerProvider provider);
    	//创建一个新的 ILogger 实例。该方法的参数 categoryName 为类日志的类别名称,它主要用来为日志指定分类名称
    	ILogger CreateLogger(string categoryName);
    }
    

    要显式指定类别,请调用 ILoggerFactory.CreateLogger

    public class ContactModel : PageModel
    {
        private readonly ILogger _logger;
    
        public ContactModel(ILoggerFactory logger)
        {
            _logger = logger.CreateLogger("MyCategory");
        }
    
        public void OnGet()
        {
            _logger.LogInformation("GET Pages.ContactModel called.");
        }
    }
    

    分组和过滤

    分组

    参考:日志作用域

    ​ 对于一组逻辑上相关的操作,将其日志信息分为一组是很有意义的,这需要使用 Scope 来实现。ILogger 接口有一个方法即BeginScope<TState>(TState state)用于创建 Scope,其中 TState 指明要创建 Scope 的标识符,它可以为任何类型的数据,一般情况下,使用字符串来指明。BeginScope<TState> 方法的返回值类型为 IDisposable,因此可以使用 using 语句块来创建 Scope,代码如下所示。

    using (logger.BeginScope("获取数据"))
    {
        logger.LogInformation("准备获取数据");
        …
        if (data == null)
        {
        logger.LogError("数据不存在");
        }
    }
    

    ​ 要在 Scope 中输出日志,除了需要创建 Scope 外,还要在ILoggerProvider 对象中启用这一功能。在添加日志提供程序时可以指定该ILoggerProvider 的一些选项。

    ​ 例如,对于 ControlProvider,只要设置ConsoleLoggerOptions 的 IncludeScopes 属性为 true,即可为其启用Scope 功能,它的默认值为 false。

    1.下列代码为控制台提供程序启用作用域:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.ClearProviders();
                    //ConsoleLoggerOptions的 IncludeScopes = true
                    logging.AddConsole(options => options.IncludeScopes = true); 
                    logging.AddDebug();
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    

    2.【推荐】以下 JSON 为控制台提供程序启用范围:

    {
      "Logging": {
        "Debug": {
          "LogLevel": {
            "Default": "Information"
          }
        },
        "Console": {
          "IncludeScopes": true, // Required to use Scopes.
          "LogLevel": {
            "Microsoft": "Warning",
            "Default": "Information"
          }
        },
        "LogLevel": {
          "Default": "Debug"
        }
      }
    }
    

    输出

    info: LoggingTest.Startup[0]
            => 获取数据
            准备获取数据
    fail: LoggingTest.Startup[0]
            => 获取数据
            数据不存在
    

    过滤

    ​ 可以通过设置最低日志级别来进行日志过滤,当这样设置后,所有低于指定日志级别的日志都不会被处理,也不会显示。例如,如果设置最低日志级别为 LogLevel.Information,那么 Debug 和 Trace 级别的日志都不会显示。

    1.SetMinimumLevel

    ​ 要设置最低日志级别,同样需要在 ConfigureLogging 方法中进行配置,此时只要调用 ILoggingBuilder 接口的 SetMinimumLevel 方法即可。

    Host.CreateDefaultBuilder(args)
    .ConfigureLogging(builder =>
    {
    builder.ClearProviders();
    builder.AddConsole(loggerOptions => loggerOptions.IncludeScopes = true);
    builder.SetMinimumLevel(LogLevel.Information);
    })
    .UseStartup<Startup>();
    

    LogLevel.None

    ​ 除了之前提到的那些级别以外,还有一个值是 None,该值高于其他所有值。如果指定这个值为最低级别,那么所有的日志都不会输出。

    2.AddFilter

    ​ 除了设置最低日志级别外,ILoggerBuilder 接口还提供了 AddFilter 方法,该方法包括多个重载,它能够指定更复杂的条件,并只显示满足条件的日志。在以下方法中,将显示 LoggeringTest.Startup 类别中,等于并高于Information 级别的日志。

    Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    {
        logging.AddConsole().AddFilter("LoggingTest.Startup", LogLevel.Information);
    })
    

    加载JSON的Logging配置

    ​ 默认情况下,在 appsettings.json 文件中包含了对日志的配置信息,要将日志配置加载并应用到程序的日志系统中,可以调用AddConfiguration 方法

    Host.CreateDefaultBuilder(args)
    .ConfigureLogging((hostingContext, logging) =>
    {
        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
    ...
    })
    .UseStartup<Startup>();
    

    ​ 在 appsettings.json 配置文件的「Logging」一节则默认包含了关于记录日志的统一配置,如 LogLevel 配置项用于设置对指定类别的日志的最低输出级别,凡是在该类别中低于指定级别的日志将不会被输出。除了设置统一配置外,还可以为每一种日志提供程序提供具体的输出配置,只要在「Logging」一节为其增加相应的配置即可,如下例添加了对 Console 类型日志提供程序的配置。

    {
        "Logging": {
                "Console": {
                    "IncludeScopes": true,
                    "LogLevel": {
                    "Microsoft.AspNetCore.Mvc.Razor": "Error",
                    "Default": "Information"
                    }
                },
                "LogLevel": {
                    "Default": "Debug"
                }
        }
    }
    
  • 相关阅读:
    zendstudio 默认网页打开your project的时候不显示本地主机localhost的解决方法
    centos安装epel源后,使用报错(Error: Cannot retrieve repository metadata (repomd.xml) for repository: epel. Please verify its path and try again)
    描述硬链接和软链接区别
    软硬链接和文件之间的关系
    硬链接 inode号码相同 文件名不同
    目录下没有任何内容,为什么该目录的硬链接数为何是2
    磁盘还有空间为什么不能写入数据以及彻底删除文件原理
    inode和block的关系
    block
    /etc/init.d和/etc/rc.d/rc*.脚本/etc/rc.d/rc.local和/etc/rc.d/rc.sysinit
  • 原文地址:https://www.cnblogs.com/tangge/p/14033479.html
Copyright © 2011-2022 走看看