〇、前言
前文已经介绍过什么是 Serilog,以及其核心特点,详见:https://www.cnblogs.com/hnzhengfy/p/19167414/Serilog_basic。
本文继续对各种类型的 Sink 进行简单的实践,主题是集中式日志与分析平台 Sinks,供参考。
此类型的 Sinks 常见的有以下五种:
Serilog.Sinks.Seq:将日志发送到 Seq 服务器。Seq 是一个专为 .NET 设计的、易于使用的集中式日志服务器,对结构化日志有原生支持,提供强大的搜索和分析功能。
Serilog.Sinks.ElasticSearch:将日志发送到 Elasticsearch 集群。Elasticsearch 是一个分布式搜索和分析引擎,与 Kibana 结合使用,是构建日志分析平台(ELK Stack)的常用选择。它能完美地索引和查询结构化日志属性。
Serilog.Sinks.Splunk:将日志发送到 Splunk 平台。Splunk 是一个强大的企业级机器数据分析平台,能够高效地处理和分析来自各种来源的结构化和非结构化数据。
Serilog.Sinks.Datadog:将日志发送到 Datadog 平台。Datadog 是一个全面的监控和分析平台,其日志管理功能可以很好地处理 Serilog 的结构化日志。
Serilog.Sinks.NewRelic:将日志发送到 New Relic 平台。New Relic 提供应用性能监控(APM)和日志管理,支持结构化日志的集成。
下边用一个表格简单介绍下它们的现状:
Sink对接平台类型开源/商业典型用户Serilog.Sinks.SeqSeq本地/私有部署日志服务器社区免费 + 商业版.NET 中小团队、初创公司Elastic.Serilog.SinksElastic(通常搭配 Kibana)开源/自建或云服务开源(Apache 2.0)DevOps 团队、多语言微服务架构Serilog.Sinks.SplunkSplunk Enterprise / Cloud商业 SIEM & 日志分析平台商业(按数据量计费)金融、安全合规、大型企业Serilog.Sinks.DatadogDatadog LogsSaaS 可观测性平台商业(按主机/日志量计费)云原生、SRE 团队、全球化公司Serilog.Sinks.NewRelicNew Relic LogsSaaS APM + Logs 平台商业(免费层有限)APM 优先、轻量级日志需求典型应用场景:
场景推荐 Sink理由.NET 单体或小型微服务,内部部署Seq快速搭建、无需运维复杂组件、完美支持 C# 结构化日志多语言微服务 + 自建日志平台Elastic统一日志入口,Kibana 强大可视化,社区生态成熟上云(AWS/Azure/GCP),追求开箱即用Datadog与 Metrics、Traces 深度集成,告警、仪表盘体验一流金融/医疗/政府,需满足审计与安全合规Splunk强大的安全信息与事件管理(SIEM)、合规报告能力一句话指南:
需求推荐选项“我是个 .NET 小团队,想要一个简单好用的日志系统”Seq“我们要构建统一日志平台,支持 Java/Go/.NET 多语言”Elastic“我们上云了,不想管基础设施,要一体化可观测性”Datadog“我们是银行,必须满足等保和审计要求”Splunk“我们已经在用 New Relic 做性能监控,想加点日志”New Relic
一、集中式日志与分析平台 Sinks 用法
这些 Sinks 是处理结构化日志的绝佳选择,因为它们专门设计用于存储、索引和查询结构化数据。本文将逐个进行简单示例。
1.1 Serilog.Sinks.Seq:将结构化日志事件发送到 Seq 服务器
Serilog.Sinks.Seq 是 Serilog 官方提供的一个 Sink(日志输出目标),用于将结构化日志事件发送到 Seq 服务器。
Seq 是由 Datalust 开发的一款专为 .NET 和结构化日志设计的日志服务器。它提供:
Web 管理界面(浏览器访问);
强大的结构化日志查询语言(类似 SQL);
实时日志流、仪表盘、告警规则;
支持 Windows、Linux、macOS 和 Docker 部署;
对 Serilog 的结构化日志(如 {UserId}、{DurationMs} 等属性)有原生支持,无需额外解析。
整个流程简单来说就是:用 Serilog 记录带属性的日志 → Seq 自动识别这些属性 → 在 Web 界面上按属性筛选、聚合、告警。
使用的大概步骤:
安装 Seq 服务器(本地或远程);
在 .NET 项目中安装 NuGet 包;
配置 Serilog,添加 Seq Sink;
记录日志并查看 Seq 界面。
下面简单实践一下。
1.1.1 安转 Seq 服务器
先下载服务器安装包,https://datalust.co/download。
Windows 可直接运行 .msi 安装包,例如:Seq-2025.2.14876.msi。安装流程很简单,一直 Next 即可,最后设置下登录信息。
或者从 Docker 启动:- docker run --rm -it -p 5341:80 datalust/seq:latest
复制代码 安装好之后通过地址访问:http://localhost:5341/。
能看到 Seq 的 UI 界面就说明安装成功了。
1.1.2 创建示例项目并修改代码
创建一个控制台应用程序。
修改 Program.cs 文件(主要就是配置 Serilog 和记录一些模拟日志):- using Serilog;
- // 配置 Serilog
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Information()
- .Enrich.WithProperty("Application", "Test12321") // 为每个项目添加一个唯一标识属性
- .WriteTo.Console() // 可选:输出到控制台
- .WriteTo.Seq("http://localhost:5341") // 发送到本地 Seq 服务器
- .CreateLogger();
- try
- {
- Log.Information("应用程序启动");
- var userId = 1001;
- var ipAddress = "1.1.1.1";
- var durationMs = 4;
- // 结构化日志:属性自动被 Seq 识别
- Log.Information("用户 {UserId} 从 {IpAddress} 登录,耗时 {DurationMs} 毫秒",
- userId, ipAddress, durationMs);
- Log.Warning("检测到异常登录尝试来自 {IpAddress}", "10.0.0.5");
- Log.Error(new InvalidOperationException("数据库连接失败"),
- "无法连接到数据库,服务器 {ServerName}", "DB-PROD-01");
- Log.Information("应用程序即将关闭");
- }
- catch (Exception ex)
- {
- Log.Fatal(ex, "应用程序发生未处理异常");
- }
- finally
- {
- Log.CloseAndFlush(); // 确保日志发送完成
- }
复制代码 1.1.3 测试一下
运行项目,查看 Seq 日志记录情况。
根据应用标识Application="Test12321",查询当前的日志:
注:还有其他筛选,例如通过属性、日志级别、时间区间等等,此处不再一一举例。
1.1.4 高级用法
- .WriteTo.Seq(
- serverUrl: "http://seq.example.com:5341",
- apiKey: "your-api-key", // 如果 Seq 启用了 API Key(在 Seq 中为某一项目配置的唯一标识)
- restrictedToMinimumLevel: LogEventLevel.Warning, // 只发送 Warning 及以上
- batchPostingLimit: 100, // 批量发送数量
- period: TimeSpan.FromSeconds(2), // 每2秒发送一次
- compact: true // 使用紧凑 JSON 格式(节省带宽)
- )
- // 生产环境中建议使用 API Key 来控制访问权限(在 Seq 界面的 Settings --> API Keys 中创建)
复制代码 1.2 Elastic.Serilog.Sinks:用于将结构化日志直接发送到 Elastic 集群
Elasticsearch 是一个分布式的搜索与分析引擎,特别适合处理大量日志数据。它能高效索引、存储和查询结构化日志,并支持全文搜索、聚合分析等。
Elastic.Serilog.Sinks 主要是 Elastic 官方自己维护的(作者:Elastic and contributors),用于将结构化日志直接发送到 Elasticsearch 集群。它自动将日志条目转换为 JSON 文档,并按时间创建索引(如 log-2025.11.05),便于在 Kibana 中可视化。
优势:
结构化日志:保留日志中的属性(如 UserId、RequestId),便于过滤和分析。
实时查询:通过 Kibana 实时查看日志、创建仪表盘。
自动索引管理:按天/周自动创建索引,避免单索引过大。
高可用支持:支持连接多个 Elasticsearch 节点,具备容错能力。
下边是一个简单的示例来对接 Elasticsearch 服务。
1.2.1 创建一个 WebAPI 项目并安装必要的包
创建一个基于 .net8 的 WebAPI 项目,并安装以下包:- dotnet add package Serilog
- dotnet add package Serilog.Sinks.Console
- dotnet add package Serilog.AspNetCore
- dotnet add package Elastic.Serilog.Sinks
复制代码 1.2.2 修改 Program.cs
- using Elastic.Channels;
- using Elastic.Ingest.Elasticsearch;
- using Elastic.Ingest.Elasticsearch.DataStreams;
- using Elastic.Serilog.Sinks;
- using Serilog;
- using Serilog.Events;
- var builder = WebApplication.CreateBuilder(args);
- // 官网介绍:https://www.elastic.co/docs/reference/ecs/logging/dotnet/serilog-data-shipper
- // 配置 Serilog
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Debug()
- .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
- .Enrich.FromLogContext()
- .WriteTo.Console()
- .WriteTo.Elasticsearch(new[] { new Uri("http://localhost:9200") }, opts =>
- {
- opts.DataStream = new DataStreamName("logs", "console-example", "demo");
- opts.BootstrapMethod = BootstrapMethod.Failure;
- opts.ConfigureChannel = channelOpts =>
- {
- channelOpts.BufferOptions = new BufferOptions
- {
- ExportMaxConcurrency = 10
- };
- };
- }, transport =>
- {
- // transport.Authentication(new BasicAuthentication(username, password));
- // transport.Authentication(new ApiKey(base64EncodedApiKey));
- })
- .CreateLogger();
- // 使用 Serilog 替换默认日志
- builder.Host.UseSerilog();
- // 其余标准配置
- builder.Services.AddControllers();
- var app = builder.Build();
- app.UseAuthorization();
- app.MapControllers();
- app.Run();
复制代码 配置 WeatherForecastController.cs 控制器:- using Microsoft.AspNetCore.Mvc;
- namespace Test.WebAPI.Serilog.WriteToFile.Controllers
- {
- [ApiController]
- [Route("[controller]")]
- public class WeatherForecastController : ControllerBase
- {
- private readonly ILogger<WeatherForecastController> _logger;
- public WeatherForecastController(ILogger<WeatherForecastController> logger)
- {
- _logger = logger;
- }
- [HttpGet]
- public IEnumerable<string> Get()
- {
- _logger.LogInformation("Fetching weather forecast for {@UserId} at {RequestTime}", "user123", DateTime.UtcNow);
- return new[] { "Sunny", "Cloudy" };
- }
- }
- public class WeatherForecast
- {
- public DateTime Date { get; set; }
- public int TemperatureC { get; set; }
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
- public string? Summary { get; set; }
- }
- }
复制代码 1.2.3 在 Docker 中安装 Elasticsearch 和 Kibana 并启动 .net 项目进行验证
注:Elasticsearch 和 Kibana 的版本必须严格一致!- // 直接使用启动按钮
- // 若本地没有 elasticsearch 会直接先下载再启动
- // 安装【elasticsearch】
- docker run -d --name elasticsearch ^
- --privileged ^
- --net elastic ^
- -p 9200:9200 -p 9300:9300 ^
- -e "discovery.type=single-node" ^
- -e "xpack.security.enabled=false" ^
- -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" ^
- --ulimit nofile=65536:65536 ^
- --ulimit nproc=4096:4096 ^
- docker.elastic.co/elasticsearch/elasticsearch:9.2.0
- // 其中:
- // --ulimit nproc=4096:4096:设置最大进程/线程数为 4096
- // --privileged:给予容器更多权限(有一定安全风险,仅用于开发)
- // --net elastic:网络配置(必须)
- // 安装【kibana】
- // 查看 Kibana 的最新版本:https://www.elastic.co/downloads/kibana
- docker run -d ^
- --name kibana ^
- --privileged ^
- --net elastic ^
- -p 5601:5601 ^
- -e "discovery__type=single-node" ^
- -e "xpack__security__enabled=false" ^
- -e "xpack__encryptedSavedObjects__encryptionKey=abcdefghijklmnopqrstuvwxyz123478" ^
- -e ELASTICSEARCH_HOSTS=http://elasticsearch:9200 ^
- -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" ^
- --ulimit nofile=65536:65536 ^
- --ulimit nproc=4096:4096 ^
- docker.elastic.co/kibana/kibana:9.2.0
- // 安装好后查看容器启动状态
- C:\Users\Administrator>docker ps -a
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- d3838724a98b docker.elastic.co/kibana/kibana:9.2.0 "/bin/tini -- /usr/l…" 7 seconds ago Up 5 seconds 0.0.0.0:5601->5601/tcp kibana
- 3c027764c6ed docker.elastic.co/elasticsearch/elasticsearch:9.2.0 "/bin/tini -- /usr/l…" 47 hours ago Up 29 minutes 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
- // 如果状态 STATUS 不为 Up,则需要查看日志,进一步查明原因
- docker logs elasticsearch
- // 或者
- docker logs kibana
复制代码 当 elasticsearch 安装好后,可以再浏览器中直接访问,因为在运行容器时已经默认把端口映射加上了,如下图就是启动成功了。
浏览器访问 http://localhost:5601/,查看 Kibana 是否加载正常。第一次加载会先初始化配置。
成功加载:(期间,需要输入六位数的密码,查看日志,查找六位数的密码:docker logs kibana)
连个服务都安装好以后,启动项目写入日志,然后在 Kibana 中查看日志记录。
1.2.4 遇到的几个问题
1)通过 kibana 网址(http://localhost:5601/)访问 elasticsearch 服务时,若访问不到 http://elasticsearch:9200 说明有可能是网络问题
查看网络配置:docker network inspect elastic
查看输出中的 Containers 部分,应该同时包含 elasticsearch 和 kibana
例如:- "Containers": {0
- "a1b2c3...": {
- "Name": "elasticsearch",
- "IPv4Address": "172.18.0.2/16"
- },
- "d4e5f6...": {
- "Name": "kibana",
- "IPv4Address": "172.18.0.3/16"
- }
- }
复制代码 2)内存问题,docker 中服务无法启动- // 查看 elasticsearch 日志
- C:\Users\Administrator>docker logs elasticsearch
- [0.002s][warning][os,thread] Failed to start thread "ArchiveWorkerThread" - pthread_create failed (EPERM) for attributes: stacksize: 1024k, guardsize: 4k, detached.
- Error occurred during initialization of VM
- Unable to create archive worker: unable to create native thread: possibly out of memory or process/resource limits reached
- // 想在 Docker Desktop 中修改,但提示:
- Resources Advanced
- You are using the WSL 2 backend, so resource limits are managed by Windows.
- You can configure limits on the memory, CPU, and swap size allocated to WSL 2 in a .wslconfig file.
复制代码 Docker Desktop 使用的是 WSL2 后端,资源限制(内存、CPU 等)不再通过 Docker Desktop GUI 设置,而是通过 Windows 的 .wslconfig 文件控制。这是 Windows 10/11 + WSL2 + Docker Desktop 的新行为(尤其在较新版本中),GUI 中的 “Resources” 设置可能被禁用或仅作参考。
打开 Windows 文件资源管理器,进入“用户”主目录(通常是:C:\Users\Administrator)。
创建一个名为 .wslconfig 的文件(注意前面有个点)。
注:如果看不到文件扩展名,请在“查看”选项卡中勾选“文件扩展名”和“隐藏的项目”。
文件内容示例(推荐用于运行 Elasticsearch):- [wsl2]
- memory=4GB # 分配给所有 WSL2 发行版的总内存
- processors=2 # CPU 核心数
- swap=2GB # 交换空间
- localhostForwarding=true
复制代码 然后查看是否修改成功:- C:\Users\Administrator>wsl --shutdown
- C:\Users\Administrator>wsl cat /proc/meminfo | findstr MemTotal
- MemTotal: 4026076 kB
复制代码 如果重新新建容器,还是报错内存不足,说明问题不是内存总量不足,而是线程创建被系统策略阻止。在 WSL2 中,这通常是因为 ulimit(用户资源限制)过低,特别是 max user processes(nproc)。
如何解决:使用 --privileged + 启动脚本(不完美但有效),在上文的启动语句中已经使用。
1.3 Serilog.Sinks.Datadog.Logs:非常适合微服务和云原生架构【收费】
注意:Serilog.Sinks.Datadog 已被遗弃,推荐使用由 Datadog 官方维护的 Serilog.Sinks.Datadog.Logs。
Serilog.Sinks.Datadog.Logs 可将 Serilog 产生的结构化日志实时发送到 Datadog 的日志摄入 API。并自动处理认证、批量发送、重试、元数据注入(如服务名、环境等)。
下边开始简单实践一下,目的是通过配置 Serilog 将日志同时输出到控制台和 Datadog。
1.3.1 创建一个控制台应用程序并引用必要的包
创建一个控制台应用程序后,在项目中添加如下包:- dotnet add package Serilog.AspNetCore
- dotnet add package Serilog.Sinks.Console
- dotnet add package Serilog.Sinks.Datadog.Logs
复制代码 若同时使用 Datadog APM(分布式追踪),需要安装专门的包:Datadog.Trace,然后再 Main 开头加上Datadog.Trace.Tracer.Initialize();,Serilog 会自动注入 dd.trace_id 和 dd.span_id,实现日志与追踪关联。
1.3.2 修改 Program.cs
- using Microsoft.AspNetCore.Builder;
- using Microsoft.Extensions.Logging;
- using Serilog;
- using Serilog.Events;
- using Serilog.Sinks.Datadog.Logs;
- using System.Data;
- using System.Text;
- Serilog.Debugging.SelfLog.Enable(Console.Error); // 打印出详细日志信息
- var builder = WebApplication.CreateBuilder(args);
- string apiKey = "af164c7b92542f64d4e0614079536d7d";
- // 配置 Serilog
- Log.Logger = new LoggerConfiguration()
- .MinimumLevel.Information()
- .WriteTo.Console() // 本地控制台输出(可选)
- .WriteTo.DatadogLogs(
- apiKey
- ,service: "chengzj-service-cz"
- , host: "chengzj-host-cz"
- //, service: "chengzj-service-zfy" // 模拟多负载时,不同服务向同一地址发送日志
- //, host: "chengzj-host-zfy"
- , configuration: new DatadogConfiguration(
- // 默认用的是 US1 站点(http-intake.logs.datadoghq.com)
- // 因此需要指定 US5 站点地址
- url: "https://http-intake.logs.us5.datadoghq.com"
- // EU 欧洲站点地址:https://http-intake.logs.datadoghq.eu
- )
- )
- .CreateLogger();
- builder.Host.UseSerilog(); // 将 Serilog 注入到 Host
- var app = builder.Build();
- // 日志记录测试
- app.MapGet("/", (ILogger<Program> logger) =>
- {
- // 发送结构化日志
- Log.Error("User {@User} logged in from {IpAddress}",
- new { Id = 123, Name = "Alice", Role = "Admin" },
- "192.168.1.100");
- logger.LogInformation("User {@User} logged in from {IpAddress}",
- new { Id = 123, Name = "Alice", Role = "Admin" },
- "192.168.1.100");
- return "Hello from .NET 8 with Datadog!";
- });
- // 手动用于测试目标地址是否正常访问
- app.MapGet("/test", async () =>
- {
- using var client = new HttpClient();
- client.DefaultRequestHeaders.Add("DD-API-KEY", apiKey);
- var json = @"[{""message"":""Test from C#""}]";
- var content = new StringContent(json, Encoding.UTF8, "application/json");
- var response = await client.PostAsync(
- "https://http-intake.logs.us5.datadoghq.com/v1/input",
- content);
- return $"Status: {response.StatusCode}, Body: {await response.Content.ReadAsStringAsync()}";
- });
- app.Run("http://localhost:5100");
复制代码 1.3.3 运行控制台应用程序测试日志发送
运行项目,查看日志写入情况,查看地址:https://us5.datadoghq.com/logs/livetail。
然后调用日志记录接口:http://localhost:5100,调用直接发送日志请求的测试接口:http://localhost:5100/test。
结构化日志记录如下图:
注意:Datadog 并非免费软件,通常为 14 天,最长也就 30 天。因此,在选用时要着重考虑下成本问题。
对于 Datadog,其 Agent 是最基础也是最常用。它的存在,就像给操作系统装了个"智能小助手"。Datadog Agent会自动收集服务器、容器、数据库等的指标,不需要太多配置就能开始监控。安装后,就能看到CPU、内存、网络等基础指标,简直像给系统装了"健康监测仪"。Datadog 还可以与云服务集成,特别是Azure。现在几乎每个企业都用云,Datadog 和 Azure 的集成特别方便。通过 Azure 门户就能一键订阅 Datadog,然后自动收集所有 Azure 资源的指标和日志,再也不用在多个平台间切换了。Datadog 还是有很多可讨论的地方,等后续再单独列举吧。
另外,还有两种常见的日志记录方式,就是 Splunk 平台、New Relic 平台,本文就暂时略过了,如下:
Serilog.Sinks.Splunk: 将日志发送到 Splunk 平台。Splunk 是一个强大的企业级机器数据分析平台,能够高效地处理和分析来自各种来源的结构化和非结构化数据。
Serilog.Sinks.NewRelic: 将日志发送到 New Relic 平台。New Relic 提供应用性能监控(APM)和日志管理,支持结构化日志的集成。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |