一、技术选型与架构设计
在微服务架构中,API网关作为流量入口,其日志系统需要满足三大核心需求:高吞吐量写入、结构化查询能力、实时可视化分析。传统ELK方案存在资源消耗大、维护复杂等问题,而Loki作为云原生时代的日志存储方案,通过标签索引和对象存储分离设计,可显著降低存储成本。
1.1 组件协同机制
- Serilog:提供结构化日志生成能力,支持多级日志过滤
- Loki:实现日志的分布式存储与标签化查询,支持水平扩展
- Grafana:构建可视化仪表盘,支持动态查询与告警集成
- Ocelot中间件:扩展请求日志上下文,注入服务标识等元数据
1.2 部署架构图
graph TDA[Ocelot网关集群] -->|日志推送| B(Serilog Sink)B -->|gRPC协议| C[Loki存储集群]C -->|查询接口| D[Grafana可视化]D -->|告警规则| E[监控告警系统]
二、环境准备与组件安装
2.1 基础环境要求
- .NET Core 3.1+运行环境
- Docker容器平台(19.03+版本)
- 对象存储服务(用于Loki持久化存储)
2.2 组件安装流程
# 安装Serilog核心包dotnet add package Serilog.AspNetCoredotnet add package Serilog.Sinks.Loki# 安装Grafana插件(可选)grafana-cli plugins install grafana-piechart-panel
建议采用分层安装策略:
- 基础层:Docker引擎、对象存储客户端
- 日志层:Serilog框架、Loki适配器
- 可视化层:Grafana及其插件系统
三、核心配置实现
3.1 Serilog配置详解
Log.Logger = new LoggerConfiguration().MinimumLevel.Override("Microsoft", LogEventLevel.Warning).Enrich.WithProperty("AppName", "ocelot-gateway").Enrich.WithMachineName().WriteTo.LokiHttp(uri: "http://loki:3100/loki/api/v1/push",labels: new[] { "app", "level", "env" },batchPostingLimit: 1000,period: TimeSpan.FromSeconds(5)).CreateLogger();
关键参数说明:
batchPostingLimit:批量写入阈值,影响吞吐量period:刷新间隔,平衡实时性与资源消耗labels:预定义标签集,决定查询维度
3.2 Loki存储优化
生产环境建议配置:
# loki-config.yaml示例storage_config:aws:s3: s3://access-key:secret-key@region/bucket-names3forcepathstyle: trueschema_config:configs:- from: 2023-01-01store: boltdb-shipperobject_store: awsschema: v12index:prefix: loki_index_period: 24h
3.3 Grafana数据源配置
-
添加Loki数据源:
- URL设置:
http://loki:3100 - 默认查询间隔:15s
- 最大数据点数:5000
- URL设置:
-
仪表盘设计原则:
- 采用PromQL风格查询语法
- 关键指标:请求速率、错误率、延迟分布
- 维度分解:按服务名、环境、版本过滤
四、高级功能实现
4.1 自定义日志中间件
public class CustomLoggingMiddleware{private readonly RequestDelegate _next;public CustomLoggingMiddleware(RequestDelegate next){_next = next;}public async Task InvokeAsync(HttpContext context){var stopwatch = Stopwatch.StartNew();var request = context.Request;try{await _next(context);stopwatch.Stop();Log.Information("Request processed {@RequestInfo}", new {Path = request.Path,Method = request.Method,StatusCode = context.Response.StatusCode,DurationMs = stopwatch.ElapsedMilliseconds,TraceId = context.TraceIdentifier});}catch (Exception ex){stopwatch.Stop();Log.Error(ex, "Request failed {@ErrorInfo}", new {Path = request.Path,Method = request.Method,StatusCode = context.Response?.StatusCode ?? 500,DurationMs = stopwatch.ElapsedMilliseconds});throw;}}}
4.2 敏感信息脱敏处理
实现ILogEventEnricher接口过滤敏感字段:
public class SensitiveDataFilter : ILogEventEnricher{public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory){if (logEvent.Properties.TryGetValue("Authorization", out var authProp)){logEvent.RemovePropertyIfPresent("Authorization");logEvent.AddOrUpdateProperty(propertyFactory.CreateProperty("Authorization","[FILTERED]"));}// 添加其他敏感字段处理逻辑...}}
4.3 高可用架构设计
建议采用三节点Loki集群部署:
[Loki写入节点] <--> [对象存储]| |[Loki查询节点] <--> [缓存层]
关键优化点:
- 写入节点:启用
-target=write模式 - 查询节点:配置
-target=read模式 - 缓存配置:使用Redis作为查询结果缓存
五、生产环境最佳实践
5.1 日志级别策略
| 环境 | Debug | Information | Warning | Error | Critical |
|---|---|---|---|---|---|
| 开发 | ✓ | ✓ | ✓ | ✓ | ✓ |
| 测试 | ✓ | ✓ | ✓ | ✓ | |
| 生产 | ✓ | ✓ | ✓ | ✓ |
5.2 查询效率优化
-
标签设计原则:
- 保持标签基数在1000以下
- 避免高频变化的标签
- 优先使用枚举型标签
-
查询语法示例:
{app="ocelot-gateway", env="prod"} |= "error" | logfmt | duration > 500ms
5.3 容量规划模型
| 指标 | 计算公式 | 示例值 |
|---|---|---|
| 日均日志量 | QPS × 日均请求数 × 单条日志大小 | 2.5GB/天 |
| 存储需求 | 日均日志量 × 保留周期 × 压缩比 | 150GB/月 |
| 查询并发 | 峰值QPS × 查询比例 × 复杂度系数 | 50 QPS |
六、故障排查指南
6.1 常见问题处理
-
日志丢失:
- 检查Loki写入队列积压情况
- 验证对象存储权限配置
- 查看Serilog重试机制配置
-
查询超时:
- 优化查询标签组合
- 增加Loki查询节点资源
- 调整
-querier.timeout参数
-
可视化异常:
- 验证Grafana数据源配置
- 检查Loki指标端点可用性
- 清除浏览器缓存重试
6.2 监控告警配置
建议设置以下关键告警规则:
- Loki写入延迟 > 5分钟
- 对象存储错误率 > 1%
- 查询响应时间 > 10s
- 日志吞吐量突降50%
通过这种集成方案,开发者可以构建出具备企业级特性的日志监控系统,既满足开发阶段的调试需求,又能支撑生产环境的稳定性保障。实际部署时建议先在测试环境验证全链路功能,再逐步推广到生产环境。