日志作用域及结构化日志组件serilog

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 上一节开始,我们学习了如何用日志框架来优雅的记录日志,这一节我们接着来学习一下日志相关的知识。

我们都知道,在netcore中存在三种生命周期,分别是Singleton、Scoped、Transient。三种生命周期分别适用于不同的场景,相应的,如果我们要对各种各样的请求进行日志记录,是否也可以考虑日志的作用域呢?除了netcore的日志框架外,是否有第三方的类似log4net之类的可多样化记录日志的方式呢?你可以先思考一下,我们下面可以一块来看一下。


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


作用域场景

  • 一个事务包含多条操作时
  • 复杂流程的日志关联时
  • 调用链追踪与请求处理过程对应时


下面,我们通过示例来看一下实际效果

首先是settings.json配置文件

{
  "logging": {
    "loglevel": {
    },
    "Console": {
      "IncludeScopes": true,
      "loglevel": {
        "default": "information",
        "_12_LoggingScopeDemo.Program": "Trace"
      }
    }
  }
}


我们通过该配置来实例化日志记录器

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("settings.json");
IConfigurationRoot configurationRoot = configurationBuilder.Build();
IServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddLogging(configure => {
    configure.AddConfiguration(configurationRoot.GetSection("logging"));
    configure.AddConsole();
    configure.AddDebug();
});
serviceDescriptors.AddSingleton<IConfiguration>(p => configurationRoot);
IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();
ILogger logger = serviceProvider.GetService<ILogger<Program>>();


然后用beginscope方法来创建日志作用域

using (logger.BeginScope("ScopedId:{scopedId}", Guid.NewGuid()))
{
    logger.LogDebug("this is debug");
    logger.LogInformation("this is information");
    logger.LogWarning("this is warning");
}
Console.WriteLine("====================");


当settings.json中的配置"IncludeScopes"为true时,即可开启日志作用域,此时运行程序结果如下

dbug: _12_LoggingScopeDemo.Program[0]
      => ScopedId:3aac90bf-ece2-4c44-9ef1-e50a789e32b2
      this is debug
info: _12_LoggingScopeDemo.Program[0]
      => ScopedId:3aac90bf-ece2-4c44-9ef1-e50a789e32b2
      this is information
warn: _12_LoggingScopeDemo.Program[0]
      => ScopedId:3aac90bf-ece2-4c44-9ef1-e50a789e32b2
      this is warning


这里,我们可以看到,程序打印出了本次的ScopedId,当IncludeScoped为false时,是不会打印该Id的,如果用while来多次输出,那么每次的id将是不同的,但一次请求内的id相同。

dbug: _12_LoggingScopeDemo.Program[0]
      => ScopedId:3aac90bf-ece2-4c44-9ef1-e50a789e32b2
      this is debug
info: _12_LoggingScopeDemo.Program[0]
      => ScopedId:3aac90bf-ece2-4c44-9ef1-e50a789e32b2
      this is information
warn: _12_LoggingScopeDemo.Program[0]
      => ScopedId:3aac90bf-ece2-4c44-9ef1-e50a789e32b2
      this is warning
      ====================
dbug: _12_LoggingScopeDemo.Program[0]
      => ScopedId:cebf0aad-9b9b-4efe-bbc6-dda375bb818a
      this is debug
info: _12_LoggingScopeDemo.Program[0]
      => ScopedId:cebf0aad-9b9b-4efe-bbc6-dda375bb818a
      this is information
warn: _12_LoggingScopeDemo.Program[0]
      => ScopedId:cebf0aad-9b9b-4efe-bbc6-dda375bb818a
      this is warning


我们再来看一下在aspnetcore中如何使用日志作用域,还是相同的配置文件,这次使用默认的aspnetcore程序来演示,只不过在默认Get方法里加以下语句

_logger.LogInformation("开始Get了");
await Task.Delay(1000);
_logger.LogInformation("Get睡醒了");


运行后,输出结果如下

info: LoggingDemo.Controllers.WeatherForecastController[0]
      => RequestPath:/weatherforecast RequestId:0HM1P8F34S8NM:00000001, SpanId:|64c643bc-4a794f2ef9a39a1a., TraceId:64c643bc-4a794f2ef9a39a1a, ParentId: => LoggingDemo.Controllers.WeatherForecastController.Get (LoggingDemo)
      开始Get了
info: LoggingDemo.Controllers.WeatherForecastController[0]
      => RequestPath:/weatherforecast RequestId:0HM1P8F34S8NM:00000001, SpanId:|64c643bc-4a794f2ef9a39a1a., TraceId:64c643bc-4a794f2ef9a39a1a, ParentId: => LoggingDemo.Controllers.WeatherForecastController.Get (LoggingDemo)
      Get睡醒了


从结果可以看出,在日志打印时,通过作用域打印了本次请求相关的路径、Id、TraceId等信息,这样的话,我们就可以在不同的请求内进行日志打印,从而通过这些这些信息来完成调用链追踪等。

这样,我们就可以在以上提到的场景使用日志作用域来更好的记录日志。


结构化日志组件Serilog:记录对查询分析友好的日志


说完日志作用域,我们再来看一下结构化日志组件Serilog,那为什么要使用结构化日志呢?

结构化日志的好处

  • 易于检索

  • 易于分析检索


那结构化日志能应用于何种场景呢?

  • 实现日志告警系统

  • 实现上下文追踪

  • 实现与追踪系统的集成


使用Serilog时,我们要先添加引用包

接着,像使用Autofac框架时一样,我们要先对框架进行注册

Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    })
    .UseSerilog(dispose: true);


Serilog通过Log.Logger来定义日志对象,该实体可选择从配置文件来生成相应配置,并通过相应的方法设置日志等级、输出方式及输出间隔等。

我们可以先来定义一个配置

public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")??"Production"}.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables()
    .Build();


通过以上配置来生成日志对象

Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(Configuration)
    .MinimumLevel.Debug()//设置最低等级level
    .Enrich.FromLogContext()
    .WriteTo.Console(new RenderedCompactJsonFormatter())
    .WriteTo.File(formatter: new CompactJsonFormatter(), "logs\\myapp.txt", rollingInterval: RollingInterval.Day)
    //.WriteTo.Debug()
    .CreateLogger();


然后在Get方法里添加一句日志输出,此时日志对象会自动被Serilog接管

_logger.LogInformation("Get 随机创建数据");


运行程序,会发现打印如下消息

{"@t":"2020-08-05T14:00:52.9976857Z","@m":"Starting web host","@i":"4872fd06"}
{"@t":"2020-08-05T14:00:55.5823856Z","@m":"Get 随机创建数据","@i":"6936e72c","SourceContext":"LoggingSerilogDemo.Controllers.WeatherForecastController","ActionId":"e012839b-6d3e-4cde-b066-6a5d2a4bb330","ActionName":"LoggingSerilogDemo.Controllers.WeatherForecastController.Get (LoggingSerilogDemo)","RequestId":"0HM1P8VS8PS5U:00000001","RequestPath":"/weatherforecast","SpanId":"|91406155-479d2c07b1fc69aa.","TraceId":"91406155-479d2c07b1fc69aa","ParentId":""}


由于我们在创建日志对象的时候选择了输出到控制台以及文件,因此,以上日志内容除了输出到控制台外,还会在配置的路径下生成一个文件夹,文件夹里的日志文件是根据配置的时间间隔来生成日志文件,可以根据需要选择时分或日月等为间隔。这样可方便的对日志进行记录并可在需要时很方便的进行检索,另外,像刚刚输出的一样,日志框架会打印出本次请求相关的上下文对象以便对请求进行追踪等。
以上便是本节的所有内容,而且到这里,日志部分也要告一段落了,对于日志部分,文章只是提到了一些基本操作,实际上还有很多其他的操作,特别是在结构化日志Serilog这里,有很多的操作方法以及日志实例化方式,大家可以通过实践慢慢摸索。

从下一节开始,我们将开始中间件的学习。


详细代码请参阅


https://github.com/IronMarmot/Samples/tree/master/CoreSamples
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
JSON Go 数据格式
Go 1.21.0 中新增的结构化日志记录标准库 log/slog 详解
Go 1.21.0 中新增的结构化日志记录标准库 log/slog 详解
153 0
|
消息中间件 安全 Dubbo
Log4j安全漏洞前车之鉴,呕心整理工作中常用开源组件避坑版本
Log4j安全漏洞前车之鉴,呕心整理工作中常用开源组件避坑版本
685 0
|
2月前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
60 1
|
8月前
|
Perl
CocoaLumberjack增强异步日志组件BITCocoaLumberjack的使用
CocoaLumberjack增强异步日志组件BITCocoaLumberjack的使用
70 1
|
3月前
|
缓存 Linux 编译器
【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案
通过上述步骤,您应该能够在CentOS环境中成功安装并使用log4cplus日志组件。面对任何安装或使用过程中出现的问题,仔细检查错误信息,对照提供的解决方案进行调整,通常都能找到合适的解决之道。log4cplus的强大功能将为您的项目提供灵活、高效的日志管理方案,助力软件开发与维护。
81 0
|
5月前
|
消息中间件 监控 搜索推荐
OpenFeign日志组件Logger原理与应用
该文章详细解释了如何在OpenFeign中配置并使用请求和响应的GZIP压缩功能。
|
5月前
|
中间件 Go 数据库
slog 简介:用于 Go 的结构化日志
slog 简介:用于 Go 的结构化日志
|
5月前
|
Kubernetes API Docker
在K8S中,如何查看kubelet组件的日志?
在K8S中,如何查看kubelet组件的日志?
|
8月前
|
SQL 数据采集 JSON
弱结构化日志 Flink SQL 怎么写?SLS SPL 来帮忙
弱结构化日志 Flink SQL 怎么写?SLS SPL 来帮忙
125645 137
|
5月前
|
数据采集 监控 Unix
性能监控之Telegraf+InfluxDB+Grafana实现结构化日志实时监控
【8月更文挑战第1天】性能监控之Telegraf+InfluxDB+Grafana实现结构化日志实时监控
353 0