一、分布式日志

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

分布式日志系统的作用就是将所有节点上的日志统一收集,存储,提供集中化的日志管理,并且提供统一的查询、分析的能力。

.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 部署比较简单,以下基于 CentOS 7 环境进行,通过以下脚本可以启动一个 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:8001 端口即可访问 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

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐