C Sharp/日誌

維基教科書,自由的教學讀本

在Microsoft.Extensions命名空間下,包Microsoft.Extensions.Logging包含用於記日誌必需的類、接口。其中最重要的是:

  • ILogger:用於記日誌,有很多擴展方法。聲明了3個方法:
    • void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter); Logger對日誌消息的寫入實現在Log方法中。Log方法的logLevel代表寫入日誌消息的等級,而日誌消息的原始內容通過參數state和exception這兩個參數來承載承載,前者代表一個原始的日誌條目(Log Entry),後者代表與之關聯的異常。日誌在被寫入之前必須格式成一個字符串,由於日誌原始信息分別由一個Object和Exception對象對象來表示,所以日誌的「格式化器」自然體現為一個Func<object, Exception, string>類型的委託對象。一條寫入的日誌消息會關聯著一個日誌記錄事件,後者則通過一個EventId對象來標識,Log方法的eventId參數類型就是EventId。EventId被定義成一個結構,它具有兩個基本的屬性Id和Name,前者代表必需的唯一標識,後者則是一個可選的名稱。除此之外,整形到EventId類型之間還存在一個隱式類型轉換,所以在需要使用EventId對象的地方,我們可以使用一個整數來代替。
    • bool IsEnabled(LogLevel logLevel); 對於任意一次日誌消息寫入請求,Logger並不會直接調用Log方法將日誌消息寫入對應的目的地,它會根據提供日誌消息的等級判斷是否應該執行寫入操作,判斷的邏輯實現在IsEnabled方法中,只有當這個方法返回True的時候它的Log方法才會被執行。
    • IDisposable BeginScope<TState>(TState state); 在默認的情況下,每次調用Logger的Log方法所進行的日誌記錄操作都是相互獨立的,但是有時候我們需要將相關的多次日誌記錄做一個邏輯關聯,或者說我們需要為多次日誌記錄操作創建一個共同的上下文範圍。這樣一個關聯上下文範圍可以通過BeginScope<TState>方法來創建,該方法將該上下文範圍與參數state表示的對象進行關聯。被創建的這個關聯上下文體現為一個IDisposable對象,我們需要調用其Dispose方法將其釋放回收,也就是說被創建的關聯上下文的生命周期終止於Dispose方法的調用。
  • ILoggerFactory:聲明了ILogger CreateLogger(string categoryName)和void AddProvider(ILoggerProvider provider)
  • ILoggerProvider:聲明了ILogger CreateLogger(string categoryName)。該接口管理、在指出logging category時創建適當的logger.
  • LoggerFactory類:內建類,實現了ILoggerFactory。用於創建Logger、增加LoggerProvider.

NET Core的日誌模型主要由三個核心對象構成,它們分別是Logger、LoggerProvider和LoggerFactory。總的來說,LoggerProvider提供一個具體的Logger對象將格式化的日誌消息寫入相應的目的地,但是我們在編程過程中使用的Logger對象則由LoggerFactory創建,這個Logger利用註冊到LoggerFactory的LoggerProvider來提供真正具有日誌寫入功能的Logger,並委託後者來記錄日誌。

例子[編輯]

首先,需要安裝nuget包:

PM> Install-Package Microsoft.Extensions.Logging
PM> Install-Package Microsoft.Extensions.Logging.Console
using System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;

namespace CoreApp2
{ 
    class Program
    {
        static void Main(string[] args)
        {
            

            var loggerFactory = LoggerFactory.Create(builder => {
                builder.AddFilter( a =>
                {
                    if (a == LogLevel.Warning)
                        return true;
                    if (a == LogLevel.Information)
                        return true;
                    if (a == LogLevel.Debug)
                        return true;
                    if (a == LogLevel.Trace)
                        return true;
                    if (a == LogLevel.Error)
                        return true;

                    //if (a == LogLevel.Critical)
                    //    return true;
                    return false;
                }).AddFilter("CoreApp2.Program", LogLevel.Critical)
                       .AddConsole();
            });
             

            ILogger logger = loggerFactory.CreateLogger<Program>();
            logger.LogInformation("Logging information.");
            logger.LogDebug("Logging debug information.");
            logger.LogTrace("Logging trace");
            logger.LogWarning("Logging warning.");
            logger.LogError("Logging error information.");
            logger.LogCritical("Logging critical information.");
        }
    }
}

另外一個例子:

using System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;  
using System.Threading;
using System.Threading.Tasks;
namespace CoreApp2
{ 
    class Program
    {
        static void Main(string[] args)
        {
            //Console.WriteLine("Hello World!");

            CreateHostBuilder(args).Build().Run();
        }

        static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureLogging(config =>
            {
                config.AddConsole();
            })
            .ConfigureServices((context, service) =>
            {
                service.AddHostedService<HostRunner>();
            });        
    }
    public class HostRunner : BackgroundService
    {
        private readonly ILogger<HostRunner> _logger;

        public HostRunner(ILogger<HostRunner> logger)
        {
            _logger = logger;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            int count = 10;
            for (int i = 0; i < count; i++)
            {
                Thread.Sleep(100);
                _logger.LogInformation("这是日志消息 {序号}/{总数}。", i, count);

            }
            return Task.CompletedTask;
        }
    }
}