You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prometheus无法采集ASP.NET Core API指标的问题排查与疑问

问题描述

我正在按照微软《使用OpenTelemetry实现.NET可观测性》文档进行集成,目前Jaeger已能正常采集追踪数据,但Prometheus无法从我的ASP.NET Core Web API采集指标数据。我采用微软TaskWeaver仓库提供的Docker Compose部署架构,当前prometheus-config.yml中配置的采集目标为optl-collector:9464,而我的ASP.NET Core Web API在https://localhost:5001/metrics端点暴露指标,我怀疑应将采集目标修改为host.docker.internal:5000,但不确定修改后optl-collector在架构中的作用。

相关配置代码

扩展类代码

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddObservabilityServices(this IServiceCollection services, IHostEnvironment environment, IConfiguration configuration)
    {
        ArgumentNullException.ThrowIfNull(services);
        ArgumentNullException.ThrowIfNull(environment);
        ArgumentNullException.ThrowIfNull(configuration);

        services.AddOpenTelemetry()
            .ConfigureResource(resource => resource
                .AddService(serviceName: environment.ApplicationName)
                .AddAttributes(new Dictionary<string, object>
                {
                    ["deployment.environment"] = environment.EnvironmentName
                }))
            .WithMetrics(metrics => metrics
                .AddAspNetCoreInstrumentation()
                .AddMeter(Metrics.SourceName)
                .AddMeter("Microsoft.AspNetCore.Hosting")
                .AddMeter("Microsoft.AspNetCore.Server.Kestrel")
                .AddPrometheusExporter())
            .WithTracing(tracing =>
            {
                tracing.AddAspNetCoreInstrumentation();
                tracing.AddHttpClientInstrumentation();
                tracing.AddSource(DistributedTracing.SourceName);
                
                // Export to Jaeger
                tracing.AddOtlpExporter(otlpOptions =>
                {
                    otlpOptions.Endpoint = new Uri("http://localhost:4317");
                });
            });

        return services;
    }

    public static IApplicationBuilder MapObservabilityEndpoints(this IApplicationBuilder app)
    {
        ArgumentNullException.ThrowIfNull(app);

        app.UseOpenTelemetryPrometheusScrapingEndpoint();

        return app;
    }
}

docker-compose.yaml

version: '3.9'

services:

  optl-collector:
    image: otel/opentelemetry-collector:0.96.0
    command: ["--config=/etc/collector-config.yaml"]
    volumes:
      - ./collector-config.yaml:/etc/collector-config.yaml
    ports:
      - "4317:4317" # Expose the gRPC receiver port for the first collector
    depends_on:
      - jaeger

  jaeger:
    image: jaegertracing/all-in-one:1.54
    ports:
      - "16686:16686" # Jaeger UI

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090" # Prometheus UI
    volumes:
      - ./prometheus-config.yml:/etc/prometheus/prometheus.yml
    command: ["--config.file=/etc/prometheus/prometheus.yml"]
    depends_on:
      - optl-collector

  grafana:
    image: grafana/grafana-enterprise:latest
    ports:
      - "3000:3000" # Grafana UI
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=secret # You should change 'secret' to a password of your choosing
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus

volumes:
  grafana_data:

collector-config.yaml

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

exporters:
  debug:
    verbosity: detailed
  otlp:
    endpoint: "jaeger:4317"
    tls:
      insecure: true
  prometheus:
    endpoint: "0.0.0.0:9464"

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlp]
    metrics:
      receivers: [otlp]
      exporters: [prometheus]
    logs:
      receivers: [otlp]
      exporters: [debug]

prometheus-config.yml

scrape_configs:
  - job_name: optl-collector
    scrape_interval: 5s
    static_configs:
      - targets: ["optl-collector:9464"]

解决方案与解释

问题根源

你的API当前是直接通过PrometheusExporter暴露了Prometheus格式的指标端点,但架构中的OTel Collector配置的是接收OTLP格式的指标,而你的API并没有把指标发送给Collector。这就导致Collector的9464端口没有任何指标数据,Prometheus去拉取自然为空。

方案一:通过OTel Collector转发指标(推荐)

这种方式符合可观测性统一管控的设计理念,Collector可以统一处理指标的过滤、聚合,再转发给Prometheus,同时保持追踪、指标的链路统一。

  1. 修改ASP.NET Core扩展类代码
    移除直接暴露Prometheus端点的配置,换成将指标通过OTLP发送给Collector:

    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddObservabilityServices(this IServiceCollection services, IHostEnvironment environment, IConfiguration configuration)
        {
            ArgumentNullException.ThrowIfNull(services);
            ArgumentNullException.ThrowIfNull(environment);
            ArgumentNullException.ThrowIfNull(configuration);
    
            services.AddOpenTelemetry()
                .ConfigureResource(resource => resource
                    .AddService(serviceName: environment.ApplicationName)
                    .AddAttributes(new Dictionary<string, object>
                    {
                        ["deployment.environment"] = environment.EnvironmentName
                    }))
                .WithMetrics(metrics => metrics
                    .AddAspNetCoreInstrumentation()
                    .AddMeter(Metrics.SourceName)
                    .AddMeter("Microsoft.AspNetCore.Hosting")
                    .AddMeter("Microsoft.AspNetCore.Server.Kestrel")
                    // 替换PrometheusExporter为OTLP Exporter,发送指标到Collector
                    .AddOtlpExporter(otlpOptions =>
                    {
                        otlpOptions.Endpoint = new Uri("http://localhost:4317");
                    }))
                .WithTracing(tracing =>
                {
                    tracing.AddAspNetCoreInstrumentation();
                    tracing.AddHttpClientInstrumentation();
                    tracing.AddSource(DistributedTracing.SourceName);
                    
                    tracing.AddOtlpExporter(otlpOptions =>
                    {
                        otlpOptions.Endpoint = new Uri("http://localhost:4317");
                    });
                });
    
            return services;
        }
    
        public static IApplicationBuilder MapObservabilityEndpoints(this IApplicationBuilder app)
        {
            ArgumentNullException.ThrowIfNull(app);
            // 移除Prometheus端点,指标现在通过Collector转发
            return app;
        }
    }
    
  2. 保持现有Collector与Prometheus配置不变
    你的collector-config.yaml已经正确配置了metrics pipeline:接收OTLP指标并转换成Prometheus格式暴露在9464端口,Prometheus继续采集optl-collector:9464即可。


方案二:Prometheus直接采集API端点

如果不想通过Collector转发指标,可以直接让Prometheus拉取API的/metrics端点,此时Collector仍负责追踪数据的中转工作。

  1. 修改Prometheus配置
    新增一个采集任务指向API的宿主机地址(Docker容器内通过host.docker.internal访问宿主机),注意API用的是HTTPS端口5001:

    scrape_configs:
      - job_name: optl-collector
        scrape_interval: 5s
        static_configs:
          - targets: ["optl-collector:9464"] # 保留,若后续有其他服务通过Collector发送指标
      - job_name: aspnet-api
        scrape_interval: 5s
        scheme: https
        tls_config:
          insecure_skip_verify: true # 自签名证书需开启此配置
        static_configs:
          - targets: ["host.docker.internal:5001"]
    
  2. OTel Collector的作用说明
    即使修改了Prometheus的采集目标,optl-collector依然是追踪数据的核心中转节点:你的API会把追踪数据通过OTLP发送给Collector,再由Collector转发到Jaeger(这也是Jaeger能正常工作的原因)。后续如果有其他服务接入可观测性,Collector可以统一管理所有追踪、指标、日志的接收与转发,无需每个服务单独对接后端工具。

内容的提问来源于stack exchange,提问作者nop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:37:32