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;
}
}
}