将 Ocelot 与 Serilog 和 Loki 集成可以实现强大的日志收集和分析能力

将 Ocelot 与 Serilog 和 Loki 集成可以实现强大的日志收集和分析能力。Loki 是一个轻量级的日志聚合系统,非常适合与 Serilog 结合使用。以下是具体实现步骤:

1. 安装必要的包

首先安装 Serilog 及其 Loki 适配器:

bash 复制代码
Install-Package Serilog.AspNetCore
Install-Package Serilog.Sinks.Loki
Install-Package Serilog.Enrichers.Environment
Install-Package Serilog.Enrichers.Thread

2. 配置 Serilog 与 Loki 集成

Program.cs 中配置 Serilog 以将日志发送到 Loki:

csharp 复制代码
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Serilog;
using Serilog.Sinks.Loki;
using System.Collections.Generic;
using System.Net.Http;

// 配置 Serilog 与 Loki 集成
Log.Logger = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .Enrich.WithEnvironmentName()
    .Enrich.WithMachineName()
    .Enrich.WithThreadId()
    .WriteTo.Console() // 同时输出到控制台
    .WriteTo.LokiHttp(
        "http://localhost:3100", // Loki 服务器地址
        new List<LokiLabel> // 添加标签用于日志过滤
        {
            new LokiLabel("app", "ocelot-gateway"),
            new LokiLabel("environment", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "production")
        },
        httpClient: new HttpClient(new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true // 忽略 HTTPS 证书验证(仅开发环境)
        }))
    .CreateLogger();

try
{
    Log.Information("Starting Ocelot gateway");
    
    var builder = WebApplication.CreateBuilder(args);
    
    // 使用 Serilog
    builder.Host.UseSerilog();
    
    // 配置 Ocelot
    builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);
    builder.Services.AddOcelot(builder.Configuration);
    
    // 其他服务配置(认证、授权等)
    // ...
    
    var app = builder.Build();
    
    // 启用自定义日志中间件(如果需要)
    app.UseMiddleware<RequestLoggingMiddleware>();
    
    // 启用认证和授权
    app.UseAuthentication();
    app.UseAuthorization();
    
    // 启用 Ocelot
    await app.UseOcelot();
    
    app.Run();
}
catch (Exception ex)
{
    Log.Fatal(ex, "Ocelot gateway terminated unexpectedly");
}
finally
{
    Log.CloseAndFlush();
}

3. 配置 Loki 连接参数

建议将 Loki 连接参数配置在 appsettings.json 中,方便管理:

csharp 复制代码
{
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning",
          "Ocelot": "Information"
        }
      },
      "Loki": {
        "Url": "http://localhost:3100",
        "ApplicationName": "ocelot-gateway",
        "TimeoutSeconds": 5
      }
    }

然后修改 Program.cs 从配置文件读取参数:

csharp 复制代码
// 从配置文件读取 Loki 配置
var lokiUrl = builder.Configuration["Loki:Url"];
var appName = builder.Configuration["Loki:ApplicationName"];

Log.Logger = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .Enrich.WithEnvironmentName()
    .Enrich.WithMachineName()
    .WriteTo.Console()
    .WriteTo.LokiHttp(
        lokiUrl,
        new List<LokiLabel>
        {
            new LokiLabel("app", appName),
            new LokiLabel("environment", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "production")
        })
    .CreateLogger();

4. 扩展自定义日志中间件以适应 Loki

修改之前的请求日志中间件,使其生成更适合 Loki 的结构化日志:

csharp 复制代码
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace OcelotGateway.Middleware
{
    public class LokiRequestLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<LokiRequestLoggingMiddleware> _logger;

        public LokiRequestLoggingMiddleware(RequestDelegate next, ILogger<LokiRequestLoggingMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var stopwatch = Stopwatch.StartNew();
            var requestTime = DateTime.UtcNow;
            
            // 保存原始响应流
            var originalResponseBodyStream = context.Response.Body;
            
            // 替换响应流以便捕获响应内容
            using (var responseBodyStream = new MemoryStream())
            {
                context.Response.Body = responseBodyStream;

                try
                {
                    // 处理请求
                    await _next(context);
                    stopwatch.Stop();

                    // 收集请求信息
                    var logData = new
                    {
                        Method = context.Request.Method,
                        Path = context.Request.Path,
                        Query = context.Request.QueryString.ToString(),
                        ClientIp = context.Connection.RemoteIpAddress?.ToString(),
                        StatusCode = context.Response.StatusCode,
                        ElapsedMs = stopwatch.ElapsedMilliseconds,
                        Timestamp = requestTime
                    };

                    // 记录结构化日志
                    _logger.LogInformation(
                        "Request processed: {Method} {Path} {StatusCode} {ElapsedMs}ms",
                        logData.Method, logData.Path, logData.StatusCode, logData.ElapsedMs,
                        logData);
                }
                catch (Exception ex)
                {
                    stopwatch.Stop();
                    _logger.LogError(ex, "Error processing request: {Method} {Path}", 
                        context.Request.Method, context.Request.Path);
                    throw;
                }
                finally
                {
                    // 将响应内容复制回原始流
                    await responseBodyStream.CopyToAsync(originalResponseBodyStream);
                    context.Response.Body = originalResponseBodyStream;
                }
            }
        }
    }
}

5. 启动 Loki 和 Grafana

为了接收和可视化日志,需要运行 Loki 和 Grafana:

  1. 使用 Docker 快速启动
bash 复制代码
# 创建 docker-compose.yml 文件
version: "3"

services:
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    volumes:
      - ./loki-config.yml:/etc/loki/local-config.yaml
    command: -config.file=/etc/loki/local-config.yaml

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    depends_on:
      - loki

volumes:
  grafana-data:
  1. 启动服务:
bash 复制代码
docker-compose up -d
  1. 在 Grafana 中添加 Loki 数据源:

6. 验证日志流程

  1. 启动 Ocelot 网关
  2. 发送一些请求到网关
  3. 在 Grafana 中创建仪表盘或使用 Explore 功能查询日志
  4. 使用标签查询示例:{app="ocelot-gateway"}

最佳实践

  1. 合理设置日志级别:在生产环境中避免过多的 Debug 日志
  2. 添加有意义的标签:如服务名、环境、版本等,便于日志过滤
  3. 敏感信息过滤:确保日志中不包含密码、令牌等敏感数据
  4. 设置超时和重试:配置 Loki 客户端的超时和重试机制
  5. 监控 Loki 健康状态:确保日志系统本身的可用性

通过这种集成方式,你可以利用 Loki 的高效日志存储和 Grafana 的强大可视化能力,构建一个完整的 Ocelot 网关日志监控系统。

相关推荐
程序员爱钓鱼2 小时前
Go语言实战案例- Redis实现简单排行榜
后端·google·go
angushine2 小时前
Spring Boot 工程启动时自动执行任务方法
java·spring boot·后端
野犬寒鸦4 小时前
力扣hot100:缺失的第一个正数(哈希思想)(41)
java·数据结构·后端·算法·leetcode·哈希算法
重生成为编程大王5 小时前
Java中使用JSONUtil处理JSON数据:从前端到后端的完美转换
java·后端·json
天若有情6736 小时前
《JAVA EE企业级应用开发》第一课笔记
java·笔记·后端·java-ee·javaee
技术小泽7 小时前
Redis-底层数据结构篇
数据结构·数据库·redis·后端·性能优化
lypzcgf8 小时前
Coze源码分析-工作空间-资源查询-后端源码
人工智能·后端·系统架构·开源·go
Funcy8 小时前
XxlJob源码分析02:admin启动流程
后端
一只叫煤球的猫8 小时前
Java实战:一个类让Java也用上JS的async/await
java·后端·性能优化
程序猿毕设源码分享网9 小时前
springboot医院信管系统源码和论文
java·spring boot·后端