一、分布式日志

日志是我们软件开发离不开的一个东西,在我们排查问题的时候日志就是我们的救命稻草。在分布式应用中,每个服务都在不停的生产日志,如果按照传统的写本地文件的日志方案,显然会面临跟修改配置一样麻烦的境地,日志被分散在储存不同的设备上,排查问题时将会非常难受。
分布式日志系统的作用就是将所有节点上的日志统一收集,存储,提供集中化的日志管理,并且提供统一的查询、分析的能力。

.net 技术栈下常用的分布式日志组件有ELK、Exceptionless、Seq。这里先介绍Seq。

二、Seq

Seq 是一款使用现代化技术构建的结构化日志存储,查询,分析工具。比起 ELK 这种组合要轻量级许多。只需要一个安装包就具有数据存储,查询,图表分析功能。它对 windows 友好,直接提供了安装包。当然也可以使用 docker 来部署。Seq 对于单个用户是免费的,这对于一些小团队并没有什么问题。Seq 一个比较强大的功能是提供了类似 Sql 语句的数
据查询及处理能力,使得用户可以直接写 Select from 来得到自己想要的数据。

Seq官方文档地址:Overview (datalust.co)

1. 安装部署

Seq可以在windows服务器下,或者通过docker部署运行。以下示例基于v2022.1版本。

1.1. docker部署

docker部署比较简单,通过以下脚本可以启动一个seq容器实例。

PH=$(echo '123456' | docker run --rm -i datalust/seq config hash)  #拉起seq镜像,并且通过seq实例命令行生成seq密码hash字符串

mkdir -p /home/yyl/seq/data # 创建数据文件目录

docker run 
--name seq 
-d
--restart unless-stopped 
-e ACCEPT_EULA=Y 
-e SEQ_FIRSTRUN_ADMINPASSWORDHASH="$PH"  # 设置默认admin用户密码
-v /home/yyl/seq/data:/data # 映射数据卷到容器外部
--memory=500m # 配置容器最大使用内存
--memory-swap=500m
-e SEQ_CACHE_SYSTEMRAMTARGET=0  # 配置不使用缓存
-p 8001:80 # 将容器端口映射到宿主机端口
-p 5341:5341
datalust/seq

上面的docker运行脚本中有几个点需要注意的。

  • Seq存储的数据包括元数据和事件数据,元数据指用户信息、Seq配置等数据,事件数据指收集到的日志数据。这两种数据默认都是直接存储在磁盘上的,所以在容器启动时,需要将数据存储的路径映射到宿主机上。事件数据只能存储在磁盘上,而元数据有需要的话可以存储到sqlserver或者postgresql,可以在容器启动之后进入容器对元数据进行迁移,可以在容器启动时通过环境变量的方式指定存储路径,如下:
    -e SEQ_METASTORE_POSTGRES_CONNECTIONSTRING="Host=localhost;Port=5432;Database=seq"
    
  • Seq实例在不指定最大内存的情况下会尽可能的占用宿主机尽可能多的内存,为了保证实例能够稳定运行,不会因为内存问题退出或者被杀掉,也为了不影响其他应用,可以为seq实例设置可用的最大内存,而通过seq提供的环境变量SEQ_CACHE_SYSTEMRAMTARGET可以配置seq是否使用缓存,在为seq容器分配的内存比较少的情况下,可以不适应缓存。
  • 当设置了admin用户的密码之后,seq将启动身份认证,如果在启动容器时没有设置,可以seq管理平台的“设置>用户”进行设置。

seq实例启动之后,通过http://localhost端口即可访问seq界面,使用admin用户和启动容器时设置密码登录。
在这里插入图片描述

1.2. windows部署

windows下的安装seq,先从官网下载安装包:Seq — centralized structured logs for . NET, Java, Node.js (datalust.co)
在这里插入图片描述
通过安装包进行安装,一直下一步即可。安装完成之后,seq应用启动,需要配置一下应用基本信息
在这里插入图片描述
在这里插入图片描述
设置完admin用户密码之后,安装就完成了。
在这里插入图片描述
在这里插入图片描述

2. .net core集成Seq

2.1. Api key

Api key作为应用程序和seq进行交互的身份凭证,通过api key可以防止未授权的应用对seq的操作。主要作用如下:

• 使用属性标记引入的事件,使其可以轻松检查和筛选
• 对日志源进行身份验证以防止意外或未经授权的写入
• 查看来自日志源的传入事件和原始 JSON 字节的速率
• 在到达时过滤事件,包括按日志级别,从而在日志记录失控的情况下减少服务器负载
• 通知日志源所需的日志记录级别,以减少网络流量

2.1.1 创建Api key

登录seq管理平台,点击"setting",第一个菜单就是 Api Key,点击“Add Api Key”进行添加。
在这里插入图片描述
在这里插入图片描述
创建api key时,可以为其分配权限,可选权限如下:
• 引入 - 将事件添加到事件存储
• 读取 - 查询事件、仪表板、信号、应用实例等。
• 写入 - 对信号、警报、首选项等的写入访问
• 项目 - 访问控制数据引入、存储、仪表板和警报的设置。
• 组织 - 访问用户帐户设置。
• 系统 - 访问与服务器配置相关的设置。

而为了禁止没有api key的日志写入,还需要启用Http/s的写入认证才行。
在这里插入图片描述

2.2. 集成

seq对.net 支持非常友好,可以通过Serilog、NLog、Log4Net、还有Microsoft.Extensions.Logging等.net 体系常用的日志记录器向seq发送日志,其中serilog是seq最推荐的。在日常工作中,我最常用的是serilog,这里也使用serilog进行演示。

2.2.1 新建一个.net 6下的Web Api工程
Install-Package Serilog.AspNetCore
Install-Package Serilog.Sinks.Async
Install-Package Serilog.Sinks.Seq
2.2.2 配置serilog

(1) 添加一个serilog.json配置文件

{
  "Serilog": {
    "WriteTo": [
      {
        "Name": "Seq",  // 配置seq日志记录器
        "Args": {
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] [{CorrelationId}] {Message:lj}{NewLine}{Exception}",
          "serverUrl": "http://localhost:5341", // seq api 地址
          "apiKey": "bCahU8jqR0cTZBrVzYhs" // api key
        }
      },
    ],
    "MinimumLevel": { // 配置日志最小级别,这里的级别是本地应用的级别,写入seq时会被Api key中配置的级别再次过滤
      "Default": "Error",
      "Override": {
        "Microsoft": "Information",
        "System": "Information",
        "Microsoft.EntityFrameworkCore": "Warning"
      }
    }
  }
}

关于 serilog的配置,这里就不细讲了。

(2) 增加serilog相关注入

改写一下program.cs

using Serilog;
	
var serilogConfigs = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("serilog.json")
    .Build();

Log.Logger = new LoggerConfiguration()      
      				.ReadFrom.Configuration(serilogConfigs)
	# if DEBUG
	                .MinimumLevel.Information()
	# endif
	                .Enrich.FromLogContext()
	# if DEBUG
	                .WriteTo.Async(c => c.Console())
	# endif
	                .CreateLogger();
	
	try
	{
	    Log.Information("Starting Host.");
	    var builder = WebApplication.CreateBuilder(args);
	
	    builder.Host.UseSerilog();
	
	    // Add services to the container.
	
	    builder.Services.AddControllers();
	    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
	    builder.Services.AddEndpointsApiExplorer();
	    builder.Services.AddSwaggerGen();
	
	    var app = builder.Build();
	
	    // Configure the HTTP request pipeline.
	    if (app.Environment.IsDevelopment())
	    {
	        app.UseSwagger();
	        app.UseSwaggerUI();
	    }
	
	    app.UseHttpsRedirection();
	
	    app.UseAuthorization();
	
	    app.MapControllers();
	
	    app.Run();
	}
	catch (Exception ex)
	{
	    Log.Fatal(ex, "Host terminated unexpectedly!");
	    throw;
	}
	finally
	{
	    Log.CloseAndFlush();
}

(3) 启动应用,查看seq
可以看到应用的日志信息已经传输到了seq中了
在这里插入图片描述
调整一下api key的接收级别为Warning
在这里插入图片描述
修改一下默认的WeatherForecastController,增加一下日志记录
在这里插入图片描述
重启应用,通过swagger请求接口
在这里插入图片描述
可以看到,应用启动时并没有再写入info级别的日志,只有调用接口之后写入的Error级别的日志。

2.3. Http接入与CLEF格式

对于日志信息的写入,Seq支持CLEF和GLEF两种格式,GLEF格式后面再将,CLEF是紧凑的 JSON 格式,这个格式可以直接通过Http 请求将信息写入seq,seq接收数据的Http Api如下:

POST https://localhost:5341/api/events/raw

为了指明传输的数据格式是CLEF格式,可以在url后面加上?clef,或者在HTTP 标头中设置ContentType=application/vnd.serilog.clef

如果需要 API 密钥,可以在 URL 中指定该密钥,加上?apiKey=apikey,也可以在 HTTP 标头中发送该密钥 X-Seq-ApiKey=apikey
在这里插入图片描述
在这里插入图片描述
可以看到,没有Api Key的时候请求是403的,而请求头加上了Api Key之后,日志写入是成功的,在seq上也可以看到日志信息。如下:
在这里插入图片描述
在这里插入图片描述
通过查看Serilog.Sink.Seq源码,可以看到Serilog.Sink.Seq最终也是通过http的方式向seq服务端发送post请求,将日志信息传输到seq的。
在这里插入图片描述
关于Seq的内容还有日志分析、服务端管理,以及seq通过GLEF格式接入其他第三方应用日志等,一篇文章写下来太长了,这些内容就放在下一篇了。

微服务系列文章:

上一篇:分布式跟踪—SkyWalking
下一篇:分布式日志—Seq(二)

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐