阮蓄 发表于 2025-11-23 23:55:09

Serilog 日志库简单实践(三)集中式日志与分析平台 Sinks(.net8)

〇、前言

前文已经介绍过什么是 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.Sinks1.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
{
   
    ")]
    public class WeatherForecastController : ControllerBase
    {
      private readonly ILogger<WeatherForecastController> _logger;
      public WeatherForecastController(ILogger<WeatherForecastController> logger)
      {
            _logger = logger;
      }
      
      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
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):

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)和日志管理,支持结构化日志的集成。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

万俟谷雪 发表于 2025-11-30 01:07:22

yyds。多谢分享

糙昧邵 发表于 前天 04:13

很好很强大我过来先占个楼 待编辑
页: [1]
查看完整版本: Serilog 日志库简单实践(三)集中式日志与分析平台 Sinks(.net8)