Java实现Prometheus指标案例

wen java案例 2

本文目录导读:

Java实现Prometheus指标案例

  1. 项目依赖配置
  2. 核心指标实现
  3. HTTP端点暴露
  4. 业务代码集成示例
  5. 主程序入口
  6. Prometheus配置
  7. Grafana仪表盘配置
  8. 测试与验证

我将为你展示一个完整的Java实现Prometheus指标的案例,包括基础指标、自定义指标以及HTTP暴露端点。

项目依赖配置

Maven配置

<dependencies>
    <!-- Prometheus Java Client -->
    <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient</artifactId>
        <version>0.16.0</version>
    </dependency>
    <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient_hotspot</artifactId>
        <version>0.16.0</version>
    </dependency>
    <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient_servlet</artifactId>
        <version>0.16.0</version>
    </dependency>
    <dependency>
        <groupId>io.prometheus</groupId>
        <artifactId>simpleclient_common</artifactId>
        <version>0.16.0</version>
    </dependency>
    <!-- Web服务器依赖 (可选,用于暴露端点) -->
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.4.48.v20220622</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>9.4.48.v20220622</version>
    </dependency>
</dependencies>

核心指标实现

自定义指标类

package com.example.prometheus;
import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import io.prometheus.client.Histogram;
import io.prometheus.client.Summary;
public class CustomMetrics {
    // 计数器(Counter)- 只增不减
    private static final Counter requestCount = Counter.build()
            .name("http_requests_total")
            .help("Total HTTP requests")
            .labelNames("method", "endpoint")
            .register();
    // 仪表盘(Gauge)- 可增可减
    private static final Gauge activeConnections = Gauge.build()
            .name("active_connections")
            .help("Active server connections")
            .register();
    // 直方图(Histogram)- 观察值分布
    private static final Histogram requestDuration = Histogram.build()
            .name("http_request_duration_seconds")
            .help("HTTP request duration")
            .labelNames("method")
            .buckets(0.1, 0.5, 1.0, 2.5, 5.0, 10.0)
            .register();
    // Summary)- 分位数统计
    private static final Summary responseSize = Summary.build()
            .name("http_response_size_bytes")
            .help("HTTP response size")
            .labelNames("endpoint")
            .quantile(0.5, 0.05)   // 中位数
            .quantile(0.9, 0.01)   // 90分位
            .quantile(0.99, 0.001) // 99分位
            .register();
    private CustomMetrics() {}
    // 记录请求
    public static void recordRequest(String method, String endpoint) {
        requestCount.labels(method, endpoint).inc();
    }
    // 记录请求耗时(支持方法链)
    public static io.prometheus.client.Histogram.Timer startRequestTimer(String method) {
        return requestDuration.labels(method).startTimer();
    }
    // 增加活跃连接
    public static void incrementActiveConnections() {
        activeConnections.inc();
    }
    // 减少活跃连接
    public static void decrementActiveConnections() {
        activeConnections.dec();
    }
    // 记录响应大小
    public static void recordResponseSize(String endpoint, double size) {
        responseSize.labels(endpoint).observe(size);
    }
}

HTTP端点暴露

Jetty服务器实现

package com.example.prometheus;
import io.prometheus.client.exporter.MetricsServlet;
import io.prometheus.client.hotspot.DefaultExports;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class MetricsServer {
    private final int port;
    private Server server;
    public MetricsServer(int port) {
        this.port = port;
    }
    public void start() throws Exception {
        // 注册JVM指标(内存、GC等)
        DefaultExports.initialize();
        server = new Server(port);
        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");
        // 添加MetricsServlet用于暴露指标
        ServletHolder metricsServlet = new ServletHolder(new MetricsServlet());
        context.addServlet(metricsServlet, "/metrics");
        server.setHandler(context);
        server.start();
        System.out.println("Metrics server started on port " + port);
    }
    public void stop() throws Exception {
        if (server != null) {
            server.stop();
        }
    }
}

业务代码集成示例

测试服务类

package com.example.prometheus;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
public class TestService {
    private static final Random random = new Random();
    private static final AtomicLong activeRequests = new AtomicLong(0);
    public static void processRequest(String endpoint) {
        String method = "GET"; // 简化示例
        try {
            // 增加活跃连接
            CustomMetrics.incrementActiveConnections();
            activeRequests.incrementAndGet();
            // 开始计时
            io.prometheus.client.Histogram.Timer timer = 
                CustomMetrics.startRequestTimer(method);
            try {
                // 模拟业务处理
                Thread.sleep(random.nextInt(1000));
                // 模拟业务结果
                double responseSize = random.nextDouble() * 1024;
                // 记录指标
                CustomMetrics.recordRequest(method, endpoint);
                CustomMetrics.recordResponseSize(endpoint, responseSize);
            } finally {
                // 停止计时
                timer.observeDuration();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 减少活跃连接
            CustomMetrics.decrementActiveConnections();
            activeRequests.decrementAndGet();
        }
    }
    public static double getActiveRequests() {
        return activeRequests.get();
    }
}

主程序入口

package com.example.prometheus;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainApplication {
    public static void main(String[] args) {
        try {
            // 启动Metrics服务器
            MetricsServer metricsServer = new MetricsServer(8080);
            metricsServer.start();
            // 模拟业务请求
            ExecutorService executor = Executors.newFixedThreadPool(10);
            for (int i = 0; i < 100; i++) {
                executor.submit(() -> {
                    String[] endpoints = {"/api/users", "/api/products", "/health"};
                    String endpoint = endpoints[random.nextInt(endpoints.length)];
                    TestService.processRequest(endpoint);
                });
            }
            // 添加运行时指标
            registerRuntimeMetrics();
            // 保持程序运行
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    metricsServer.stop();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }));
            // 阻塞主线程
            Thread.currentThread().join();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void registerRuntimeMetrics() {
        // 自定义运行时指标
        Gauge buildInfo = Gauge.build()
            .name("application_build_info")
            .help("Application build information")
            .labelNames("version", "environment")
            .register();
        buildInfo.labels("1.0.0", "production").set(1);
        // 自定义业务指标
        Counter businessEvents = Counter.build()
            .name("business_events_total")
            .help("Business events counter")
            .labelNames("event_type", "status")
            .register();
        // 模拟业务事件
        for (int i = 0; i < 50; i++) {
            businessEvents.labels("order_created", "success").inc();
            if (i % 5 == 0) {
                businessEvents.labels("order_created", "failed").inc();
            }
        }
    }
}

Prometheus配置

prometheus.yml自定义配置

scrape_configs:
  - job_name: 'java-app'
    scrape_interval: 15s
    static_configs:
      - targets: ['localhost:8080']
    metrics_path: /metrics

Grafana仪表盘配置

简单仪表盘JSON配置示例

{
  "panels": [
    {
      "title": "HTTP请求量",
      "type": "graph",
      "targets": [
        {
          "expr": "rate(http_requests_total[5m])",
          "legendFormat": "{{method}} - {{endpoint}}"
        }
      ]
    },
    {
      "title": "请求耗时分布",
      "type": "graph",
      "targets": [
        {
          "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))",
          "legendFormat": "p99"
        }
      ]
    },
    {
      "title": "活跃连接数",
      "type": "graph",
      "targets": [
        {
          "expr": "active_connections",
          "legendFormat": "connections"
        }
      ]
    }
  ]
}

测试与验证

查询指标文件

# 查看所有指标
curl http://localhost:8080/metrics
# 查看特定指标
curl http://localhost:8080/metrics | grep http_request
# 使用PromQL查询
curl 'http://localhost:9090/api/v1/query?query=rate(http_requests_total[5m])'

预期输出示例

# TYPE http_requests_total counter
http_requests_total{endpoint="/api/products",method="GET"} 32.0
http_requests_total{endpoint="/api/users",method="GET"} 35.0
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{method="GET",le="0.1"} 10.0
http_request_duration_seconds_bucket{method="GET",le="0.5"} 45.0
http_request_duration_seconds_sum{method="GET"} 123.456
http_request_duration_seconds_count{method="GET"} 100.0
# TYPE active_connections gauge
active_connections 5.0

这个案例展示了完整Prometheus指标监控方案,包含了所有主要指标类型、自定义指标、运行时指标注册以及HTTP暴露端点,你可以根据实际需求进行调整和扩展。

抱歉,评论功能暂时关闭!