当前位置: 首页 > news >正文

ABP VNext + Grafana Loki:集中式日志聚合

📝 ABP VNext + Grafana Loki:集中式日志聚合


📚 目录

  • 📝 ABP VNext + Grafana Loki:集中式日志聚合
    • 一、引言
      • ✨ TL;DR
    • 二、环境与依赖
      • 🛠️ 平台版本
      • 🔗 NuGet 包
      • ⚙️ 基础服务
    • 三、Serilog + Loki 集成
      • 3.1 安装与配置
      • 3.2 添加标签
    • 四、Loki 数据源与推送格式
      • 错误处理与重试机制
    • 五、Grafana 配置
      • 5.1 新建 Loki Data Source
      • 5.2 日志面板(Explore)
    • 六、仪表盘与告警
      • 6.1 自定义仪表盘
      • 6.2 告警规则
      • 告警通知配置
    • 七、多服务与多环境
      • 📦 统一标签策略
      • 🔄 Grafana Dashboard 复用
      • Grafana Provisioning
    • 八、性能与可靠性最佳实践
      • ⚙️ 批量/缓冲
      • 💾 Durable Sink 保障可靠性
      • 📊 Loki 索引策略
      • ⚡ Loki 高可用部署
    • 九、端到端示例
    • 日志流转流程


一、引言

✨ TL;DR

  • Serilog 将 ABP 应用日志推送到 Grafana Loki,实现结构化、标签化存储,便于查询和追踪。
  • Grafana 中配置日志面板、查询模板与告警规则,支持多服务多环境的统一日志聚合。
  • 实现高可用、可扩展的日志管理体系,轻松定位问题并提高运维效率。

📚 背景与动机
在 ABP 微服务架构下,日志分散在多个服务实例中,排查问题时需要登录多个实例查看日志,运维成本高且不便实时监控。Grafana Loki 通过仅索引日志的标签,结合 Grafana 原生支持,能够实现零运维的集中式日志解决方案,极大提升查询性能与可用性。本教程展示了如何在 ABP VNext 应用中,结合 Serilog 和 Grafana Loki 构建高效、可复现的日志管理系统。


二、环境与依赖

🛠️ 平台版本

  • .NET 6 + ABP VNext 6.x
  • Grafana ≥ 9.xLoki ≥ 2.x

🔗 NuGet 包

  • Serilog.AspNetCore
  • Serilog.Sinks.Grafana.Loki(支持 /loki/api/v1/push 接口)
  • Serilog.Formatting.Compact(结构化 JSON 格式)

⚙️ 基础服务

  • Loki ▶ HTTP 接收器(<loki_host>:3100
  • Grafana ▶ 配置 Data Source 指向 Loki

三、Serilog + Loki 集成

3.1 安装与配置

首先在项目中安装必需的 NuGet 包:

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Grafana.Loki
dotnet add package Serilog.Formatting.Compact

Program.cs 中进行 Serilog 配置:

using Serilog;
using Serilog.Formatting.Compact;Log.Logger = new LoggerConfiguration().Enrich.FromLogContext().Enrich.WithProperty("Application", "OrderService").Enrich.WithProperty("Environment", builder.Environment.EnvironmentName).Enrich.WithProperty("TraceId", Activity.Current?.TraceId.ToString() ?? "unknown").Enrich.WithProperty("TenantId", "Tenant123").WriteTo.Console(new RenderedCompactJsonFormatter()).WriteTo.GrafanaLoki("http://loki:3100", labels: new Dictionary<string, string>{{ "Application", "OrderService" },{ "Environment", builder.Environment.EnvironmentName }}).CreateLogger();builder.Host.UseSerilog();

3.2 添加标签

为了进一步增强日志的可查询性,可以在日志中加入更多的标签,如 TraceIdTenantId,使得日志查询更加精确。

Log.Logger = new LoggerConfiguration().Enrich.FromLogContext().Enrich.WithProperty("Application", "OrderService").Enrich.WithProperty("Environment", builder.Environment.EnvironmentName).Enrich.WithProperty("TraceId", Activity.Current?.TraceId.ToString() ?? "unknown").Enrich.WithProperty("TenantId", "Tenant123").WriteTo.Console(new RenderedCompactJsonFormatter()).WriteTo.GrafanaLoki("http://loki:3100", labels: new Dictionary<string, string>{{ "Application", "OrderService" },{ "Environment", builder.Environment.EnvironmentName }}).CreateLogger();

四、Loki 数据源与推送格式

Loki Push API 的日志数据格式要求如下:

{"streams": [{"stream": { "label1": "value1", "label2": "value2" },"values": [[ "1621373445000000000", "log line 1" ],[ "1621373446000000000", "log line 2" ]]}]
}

Serilog.Sinks.Grafana.Loki 会自动批量打包日志,并推送到 Loki。每条日志会自动包装成这种 JSON 格式,因此你不需要自己处理日志格式。

错误处理与重试机制

为了确保日志的可靠性,当 Loki 推送失败时,我们可以使用 Serilog Sink 的失败重试机制,或者将失败日志临时保存在本地文件中进行重试。以下是配置重试机制的示例:

.WriteTo.GrafanaLoki("http://loki:3100", labels: new Dictionary<string, string> {{"Application", "OrderService"}})
.WithAutomaticRetries(maxRetries: 5, delayBetweenRetries: TimeSpan.FromSeconds(5))

五、Grafana 配置

5.1 新建 Loki Data Source

在 Grafana 中创建 Loki 数据源:

  1. 在 Grafana 控制台选择 Data Sources,点击 Add Data Source
  2. 选择 Loki,输入 Loki 的地址 http://<loki_host>:3100,然后点击 Save & Test 验证连接是否成功。

5.2 日志面板(Explore)

示例查询

{Application="OrderService", Environment="Production"}|= "Error"|= "Exception"

使用模板变量 $app$env 来动态切换服务和环境:

{Application="$app", Environment="$env"} |= "Error"

六、仪表盘与告警

6.1 自定义仪表盘

每分钟日志量

count_over_time({Application="$app"}[1m])

错误级别趋势

rate({level="Error",Application="$app"}[5m])

请求延迟分布(假设记录了 Duration 字段):

histogram_quantile(0.95, sum(rate({Application="$app"} |= "Duration" [$__interval])) by (le))

推荐的布局包括概览、异常详情、容量监控。

6.2 告警规则

示例告警规则

  • Rule 1:5 分钟内 Error 日志 ≥ 50 ▶ 发送通知。
  • Rule 2:日志包含关键异常关键字(如 NullReferenceException)▶ 立即告警。

通知渠道:Email、Slack、Teams。

告警通知配置

Grafana 支持将告警通知集成到 Slack、Teams、Email 等渠道。在 Grafana 的 Alerting 设置中,可以创建通知渠道,并将其配置到特定告警规则中。


七、多服务与多环境

📦 统一标签策略

为了在不同环境和服务之间聚合日志,推荐使用统一的标签策略:ApplicationEnvironmentTenant 等。这样可以帮助开发者在查询日志时使用一致的命名方式。

🔄 Grafana Dashboard 复用

通过模板变量,如 $app$env,实现多实例监控,避免重复配置。你可以在一个 Grafana 仪表盘中查看多个服务和环境的数据,只需动态切换模板变量即可。

Grafana Provisioning

为了自动化管理多个 Grafana 实例的配置,可以使用 Provisioning 功能,将仪表盘和数据源配置文件化,从而实现批量部署和配置同步。


八、性能与可靠性最佳实践

⚙️ 批量/缓冲

调整 batchPostingLimitperiod 配置,以优化推送频率和批量大小。不同的日志 Sink 可能有不同的配置选项,请参考官方文档调整。

💾 Durable Sink 保障可靠性

为了确保日志的可靠性,建议配置带本地文件缓冲的 Durable Sink,例如:

.WriteTo.DurableHttpUsingFileSizeRolledBuffers("http://loki:3100", fileSizeLimitBytes: 50_000_000)

📊 Loki 索引策略

  • 避免标签的高基数(Cardinality),如每个日志条目的 UserIdSessionId
  • 只使用必要的标签,避免过多的字段导致存储和查询性能下降。

⚡ Loki 高可用部署

对于生产环境,建议将 Loki 部署为分布式系统,使用 DistributorIngesterQuerier 等组件来提升可用性和水平扩展能力。可以使用 Docker Compose 或 Kubernetes 配置 Loki 集群。


九、端到端示例

  1. 启动 Loki & Grafana Docker 容器
    使用以下 docker-compose.yml 启动 Loki 和 Grafana:

    version: '3.7'
    services:loki:image: grafana/loki:2.8.2command: -config.file=/etc/loki/local-config.yamlports:- "3100:3100"grafana:image: grafana/grafana:9.5.0ports:- "3000:3000"
    
  2. 配置 ABP 项目 Serilog
    在 ABP 项目的 Program.cs 中按照 3.1 配置 Serilog。

  3. 生成多级别日志
    在代码中添加不同级别的日志:Log.Information(), Log.Warning(), Log.Error()

  4. 在 Grafana Explore 中执行查询
    使用示例查询来可视化日志。

  5. 创建告警规则
    设置一个告警规则,并模拟触发 Error 日志来测试告警。


日志流转流程

ABP 应用
Serilog
Loki Push API
Distributor
Ingester
Querier
Loki
Grafana
日志查询与可视化
告警通知

http://www.lryc.cn/news/593927.html

相关文章:

  • 【Django】DRF API版本和解析器
  • Kubernetes (K8S)知识详解
  • 基于bert-lstm对微博评论的情感分析系统设计与实现
  • JVM-Java
  • Web服务压力测试工具hey学习一:使用方法
  • Django ORM系统
  • PyQt5—QColorDialog 学习笔记
  • 7-20 关于mysql
  • 【企业架构】TOGAF概念之一
  • 基于SHAP的特征重要性排序与分布式影响力可视化分析
  • Shell脚本-cut工具
  • 零基础学习性能测试第一章-理解程序运行原理,需要什么资源
  • 第十四届全国大学生数学竞赛初赛试题(非数学专业类)
  • CSS 单位完全指南:掌握 em、rem、vh、vw 等响应式布局核心单位
  • gradle微服务依赖模版
  • PHPStorm携手ThinkPHP8:开启高效开发之旅
  • 用 Jetpack Compose 写 Android 的 “Hello World”
  • RCE随笔(1)
  • RK3588 安卓adb操作
  • C++ - 仿 RabbitMQ 实现消息队列--服务端核心模块实现(一)
  • RK3588 编译 Android 13 镜像方法
  • 状态管理与团队协作 - SRE 的核心关切
  • c#:TCP服务端管理类
  • 第一章: 初识 Redis:背后的特性和典型应用场景
  • c#:管理TCP服务端发送数据为非16进制
  • 网络原理——IP
  • CentOS 服务器docker pull 拉取失败
  • Docker 在 Ubuntu 系统中的详细操作指南
  • 【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
  • Docker实战:使用Docker部署envlinks极简个人导航页