Grafana观测日志/指标

在.NET Core Web API中集成Grafana生态系统的监控工具链,实现全栈可观测性(日志、指标、追踪)

本文在此使用下面组件:

  • Grafana:用于监控和观测数据
  • Prometheus:指标(Metrics)收集
  • Loki:日志收集
  • Alloy:统一观测数据收集器

Grafana 是可视化层,用于展示 Prometheus(指标)、Loki(日志) 和 Tempo(追踪) 的数据。

Alloy 是数据收集层,统一采集指标、日志、追踪并转发到对应后端(Prometheus/Loki/Tempo)。

它们共同构成完整的 观测性栈(Observability Stack):Alloy(收集) → Prometheus/Loki/Tempo(存储) → Grafana(可视化)

部署Grafana服务

使用docker compose编排grafana相关服务:

yaml 复制代码
services:
  grafana-alloy:
    image: grafana/alloy:latest
    container_name: grafana-alloy
    restart: unless-stopped
    volumes:
      - /etc/grafana-config/alloy/config.alloy:/etc/alloy/config.alloy
      - /etc/grafana-config/alloy/data:/var/lib/alloy
    ports:
      - "12345:12345"  # 用于 Alloy 的 HTTP 服务器
      - "4317:4317"    # OpenTelemetry gRPC 接收器
      - "4318:4318"    # OpenTelemetry HTTP 接收器
      - "8888:8888"    # 用于 Prometheus 远程写入
    command: ["run", "--server.http.listen-addr=0.0.0.0:12345", "/etc/alloy/config.alloy"]
  loki:
     image: grafana/loki:3.0.0
     ports:
       - "3100:3100"
     command: -config.file=/etc/loki/local-config.yaml
  prometheus:
     image: prom/prometheus:v2.47.0
     command:
       - --web.enable-remote-write-receiver
       - --config.file=/etc/prometheus/prometheus.yml
     ports:
       - "9090:9090"
  grafana:
     environment:
       - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
       - GF_AUTH_ANONYMOUS_ENABLED=true
       - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
     entrypoint:
       - sh
       - -euc
       - |
         mkdir -p /etc/grafana/provisioning/datasources
         cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
         apiVersion: 1
         datasources:
         - name: Loki
           type: loki
           access: proxy
           orgId: 1
           url: http://loki:3100
           basicAuth: false
           isDefault: false
           version: 1
           editable: false
         - name: Prometheus
           type: prometheus
           orgId: 1
           url: http://prometheus:9090
           basicAuth: false
           isDefault: true
           version: 1
           editable: false
         EOF
         /run.sh
     image: grafana/grafana:latest
     ports:
       - "13000:3000"
volumes:
  grafana-storage: {}

构建容器

通过ip:13000(端口根据自己的配置调整)来访问grafana

grafana已经根据我们的配置预先设置好了Loki和Prometheus。

查看Loki:

查看Prometheus:

配置Alloy

找到alloy配置文件config.alloy,如本文配置文件挂载在/etc/grafana-config/alloy/config.alloy,打开并修改:

yaml 复制代码
//配置收集/var/log/ 目录下的所有.log文件
local.file_match "local_files" {
     path_targets = [{"__path__" = "/var/log/*.log"}]
     sync_period = "5s"
}
loki.source.file "log_scrape" {
    targets    = local.file_match.local_files.targets
    forward_to = [loki.process.filter_logs.receiver]
    tail_from_end = true
}
loki.process "filter_logs" {
    stage.drop {
        source = ""
        expression  = ".*Connection closed by authenticating user root"
        drop_counter_reason = "noisy"
      }
    forward_to = [loki.write.grafana_loki.receiver]
}
//配置收集/tmp/alloy-logs/ 目录下的所有.log文件
local.file_match "tmplogs" {
    path_targets = [{"__path__" = "/tmp/alloy-logs/*.log"}]
}

loki.source.file "local_files" {
    targets    = local.file_match.tmplogs.targets
    forward_to = [loki.write.grafana_loki.receiver]
}
//将收集的日志写入loki
loki.write "grafana_loki" {
    endpoint {
      url = "http://loki:3100/loki/api/v1/push"
      // basic_auth {
      //  username = "admin"
      //  password = "admin"
      // }
    }
}

//配置本地系统指标导出器
prometheus.exporter.unix "local_system" { }

//配置发送源与时间间隔
prometheus.scrape "scrape_metrics" {
  targets         = prometheus.exporter.unix.local_system.targets
  forward_to      = [prometheus.relabel.filter_metrics.receiver]
  scrape_interval = "10s"
}
prometheus.relabel "filter_metrics" {
  rule {
    action        = "drop"
    source_labels = ["env"]
    regex         = "dev"
  }

  forward_to = [prometheus.remote_write.metrics_service.receiver]
}
//将收集的指标写入prometheus
prometheus.remote_write "metrics_service" {
    endpoint {
        url = "http://prometheus:9090/api/v1/write"
        // basic_auth {
        //   username = "admin"
        //   password = "admin"
        // }
    }
}

访问Alloy UI查看配置间的关系图:

测试收集数据

直接向loki端点发送数据:

plain 复制代码
NOW=$(date +%s%N)
curl -v -XPOST "http://localhost:3100/loki/api/v1/push" \
  -H "Content-Type: application/json" \
  -d '{
    "streams": [{
      "stream": { "job": "test" },
      "values": [ [ "'"$NOW"'", "test log" ] ]
    }]
  }'

在Grafana中查看:

向本地文件写入log日志echo "New log line" >> /tmp/alloy-logs/log.log

可以查到收集的日志信息:

在Net Core应用程序中收集指标与日志

  1. 添加相应的包
plain 复制代码
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Instrumentation.SqlClient
dotnet add package OpenTelemetry.Instrumentation.Runtime
//使用 Serilog 将日志发送到 Loki
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Grafana.Loki
  1. 编辑启动程序代码:
plain 复制代码
// 1. 配置 OpenTelemetry 资源(服务名、版本等)
var resourceBuilder = ResourceBuilder
    .CreateDefault()
    .AddService(serviceName: "my-webapi", serviceVersion: "1.0.0");
// 2. 配置 Tracing(分布式追踪)
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .SetResourceBuilder(resourceBuilder)
            .AddAspNetCoreInstrumentation() // 监控 ASP.NET Core 请求
            .AddHttpClientInstrumentation()   // 监控 HttpClient 请求
            .AddSqlClientInstrumentation()    // 监控 SQL 查询
            .AddOtlpExporter(options =>       // 发送到 Alloy 的 OTLP 接收端
            {
                options.Endpoint = new Uri("http://grafana-alloy:4317"); // Docker 内部网络
            });
    });
// 3. 配置 Metrics(指标)
builder.Services.AddOpenTelemetry()
    .WithMetrics(metrics =>
    {
        metrics
            .SetResourceBuilder(resourceBuilder)
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddRuntimeInstrumentation()   // 监控 .NET 运行时指标
            .AddOtlpExporter(options =>       // 发送到 Alloy
            {
                options.Endpoint = new Uri("http://grafana-alloy:4317");
            });
    });
// 4. 配置 Logging(日志)
builder.Logging.AddOpenTelemetry(logging =>
{
    logging.SetResourceBuilder(resourceBuilder)
        .AddOtlpExporter(options =>
        {
            options.Endpoint = new Uri("http://grafana-alloy:4317");
        });
});
builder.Host.UseSerilog(); // 启用 Serilog
  1. 在alloy.config中添加下面配置
plain 复制代码
otelcol.receiver.otlp "default" {
  grpc { endpoint = "0.0.0.0:4317" }
  http  { endpoint = "0.0.0.0:4318" }

  output {
    metrics = [otelcol.exporter.prometheus.default.input]
    logs    = [otelcol.exporter.loki.default.input]
    traces  = []
  }
}
otelcol.exporter.loki "default" {
  forward_to = [loki.write.grafana_loki.receiver]  // 转发到 Loki Write
}
otelcol.exporter.prometheus "default" {
  forward_to = [prometheus.remote_write.metrics_service.receiver]  // 转发到 Prometheus
}
  1. 选择一个仪表盘模板展示数据
  1. 查看仪表盘
相关推荐
兆。2 小时前
电子商城后台管理平台-Flask Vue项目开发
前端·vue.js·后端·python·flask
weixin_437398212 小时前
RabbitMQ深入学习
java·分布式·后端·spring·spring cloud·微服务·rabbitmq
西京刀客7 小时前
Go多服务项目结构优化:为何每个服务单独设置internal目录?
开发语言·后端·golang
李匠20247 小时前
C++GO语言微服务之gorm框架操作MySQL
开发语言·c++·后端·golang
源码云商8 小时前
基于Spring Boot + Vue的高校心理教育辅导系统
java·spring boot·后端
黄俊懿9 小时前
【深入理解SpringCloud微服务】手写实现一个微服务分布式事务组件
java·分布式·后端·spring·spring cloud·微服务·架构师
Themberfue9 小时前
RabbitMQ ②-工作模式
开发语言·分布式·后端·rabbitmq
有梦想的攻城狮10 小时前
spring中的@Inject注解详情
java·后端·spring·inject
曼岛_10 小时前
[架构之美]Spring Boot多环境5种方案实现Dev/Test/Prod环境隔离
spring boot·后端·架构
Top`10 小时前
服务预热原理
java·后端·spring