0%

NetCore中的日志框架

Logger的级别和日志的使用

  • 级别从低到高分别是Trace,Debug,Information,Warning,Error,Critical,None,我们可以在配置文件中定义我们的配置级别
  • trace一般在定义组件的内部使用,记录详细的执行过程信息,用以暴露给组件使用者。
  • debug与trace很像,但一般仅在有调试意图的位置记录,且更多地是给组件的开发者自己查看。
  • info则是在业务场景、服务调用场景等更贴近业务实现部分的信息记录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"LogLevel": {
"Default": "Information",
"Program": "Trace",
"alogger": "Trace",
"LoggingDemo.OrderService": "Trace"
}
},
"Debug": {
"LogLevel": {
"Default": "Information",
"Program": "Trace",
"alogger": "Trace",
"LoggingDemo.OrderService": "Trace"
}
}
}
}
  • 使用ILoggerFactory获取日志对象和日志的输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//从配置文件获取配置对象
ConfigurationBuilder builder = new ConfigurationBuilder();
var dir = Path.GetFullPath("../../..");
builder.AddJsonFile($"{dir}/appsettings.json", false, true);
var configurationRoot = builder.Build();

IServiceCollection serviceCollection = new ServiceCollection();
//用工厂模式将配置对象注册到容器中
serviceCollection.AddSingleton<IConfiguration>(p => configurationRoot);
//往容器中添加日志的配置,添加Logging节点、Console节点和Debug节点的配置信息
serviceCollection.AddLogging(loggingBuilder =>
{
loggingBuilder.AddConfiguration(configurationRoot.GetSection(""));
loggingBuilder.AddConsole();
loggingBuilder.AddDebug();
});
//注册OrderService服务
serviceCollection.AddTransient<OrderService>();

//从容器中获取日志工厂,用loggerFactory来创建一个日志记录器
IServiceProvider service = serviceCollection.BuildServiceProvider();
ILoggerFactory loggerFactory = service.GetService<ILoggerFactory>();

//输出日志
var alogger = loggerFactory.CreateLogger("alogger");
alogger.LogDebug(2001, "alogger:Log from debug.");
alogger.LogInformation(2001, "alogger:Log from information.");
alogger.LogError(2001, "alogger:Log from error.");
alogger.LogWarning(2001, "alogger:Log from warning.");
alogger.LogCritical(2001, "alogger:Log from critical.");
  • 使用ILogger获取日志对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//在这里logger对象是通过构造函数注入的,这个日志对象的级别是在LoggingDemo.OrderService中定义的,即类的命名空间
public class OrderService
{
private ILogger<OrderService> _logger;

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

public void Show()
{
//建议使用模板来组织我们的输出字符串,而不是用拼接字符串的形式
_logger.LogInformation("Show Time {time}", DateTime.Now);
}
}

//从容器中获取OrderService
var order = service.GetService<OrderService>();
order.Show();
  • 注意,日志中要避免出现敏感信息,如密码、密钥等。

日志的作用域,解决不同请求间的日志干扰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var logger = service.GetService<ILogger<Program>>();
while (Console.ReadKey().Key!=ConsoleKey.Escape)
{
//创建一个日志作用域,在该作用域范围内使用一个日志对象进行日志记录
//BeginScope是用来标识作用域的,在实际使用时scopeId可以换成不同的Id
using (logger.BeginScope("ScopeId:{scopeId}", Guid.NewGuid()))
{
logger.LogInformation("Info");
logger.LogError("Error");
logger.LogTrace("Trace");
}
Thread.Sleep(100);
Console.WriteLine("======================================");
}
  • 在web中的Id

    1. requestId 表示当前请求的唯一标识,每此请求都会有一个id
    2. traceId 表示当前请求链路的唯一标识,在例如,这个请求进来,然后这个服务会调用其它服务,则整个链路上的请求,都会携带这个相同的traceId
    3. spanId,表示同一个请求链路上不同节点的标识。
    4. traceId + spanId 可以实现分布式追踪。
  • 关于BeginScope,一般由框架调用,例如controller的action中,不需要些这些代码。
    在设计自己的组件,也是类似的。

结构化日志组件Serilog

  • 使用结构化日志的好处:易于检索、易于分析统计
  • 场景:日志告警、上下文关联、与追踪系统集成
  • 使用Serilog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class Program
{
//获取配置文件信息
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", false, true)
.AddEnvironmentVariables()
.Build();
public static void Main(string[] args)
{
//以json格式输出日志
//Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration)
// .MinimumLevel.Debug()
// .Enrich.FromLogContext()
// .WriteTo.Console(new RenderedCompactJsonFormatter())
// .WriteTo.File(formatter: new CompactJsonFormatter(), "logs\\myapp-json.txt",
// rollingInterval: RollingInterval.Day)
// .CreateLogger();

//以默认格式输出
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration)
.MinimumLevel.Debug()
//把Microsoft的日志级别重写成Information
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File(Path.Combine("logs", @"log.txt"), rollingInterval: RollingInterval.Day)
.CreateLogger();
try
{
Log.Information("Starting web host");
CreateHostBuilder(args).Build().Run();
}
catch (Exception e)
{
Log.Fatal(e, "Host terminated error");
Console.WriteLine(e);
throw;
}
finally
{
Log.CloseAndFlush();
}

}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseSerilog(dispose:true);
}
-------------本文结束感谢您的阅读-------------