C Sharp/日誌
< 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;
}
}
}