Skip to content

Instantly share code, notes, and snippets.

@ravin-singh
Last active October 25, 2021 07:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ravin-singh/8654b654163c508cdb227a621fe078f0 to your computer and use it in GitHub Desktop.
Save ravin-singh/8654b654163c508cdb227a621fe078f0 to your computer and use it in GitHub Desktop.
Micrometer metrics exporter for apache http connection pool
1. Create a scheduler to add new routes
@Scheduled(fixedRate = 300000)
public void updateHttpRoutes() {
Set<HttpRoute> routes = poolingHttpClientConnectionManager.getRoutes();
for (HttpRoute route : routes) {
httpMetricsTracker.add(route, poolingHttpClientConnectionManager);
}
}
@ravin-singh
Copy link
Author

@service
public class HttpMetricsTracker {
private static final String HTTP_METRIC_NAME_PREFIX = "httpcp";
private static final String METRIC_NAME_LEASED_CONNECTIONS = HTTP_METRIC_NAME_PREFIX + ".connections.leased";
private static final String METRIC_CATEGORY = "http_pool";
private static final String METRIC_NAME_AVAILABLE_CONNECTIONS = HTTP_METRIC_NAME_PREFIX + ".connections.available";
private static final String METRIC_NAME_PENDING_CONNECTIONS = HTTP_METRIC_NAME_PREFIX + ".connections.pending";
private static final String METRIC_NAME_MAX_CONNECTIONS = HTTP_METRIC_NAME_PREFIX + ".connections.max";

private final Map<String, HttpPoolStats> poolStatsMap = new ConcurrentHashMap<>();
private final MeterRegistry meterRegistry;

@Autowired
public HttpMetricsTracker(MeterRegistry meterRegistry) {
    this.meterRegistry = meterRegistry;
}

private void createGauge(String poolName, HttpPoolStats poolStats, MeterRegistry meterRegistry) {
    Gauge.builder(METRIC_NAME_AVAILABLE_CONNECTIONS, poolStats, HttpPoolStats::getAvailable)
            .description("Available connections")
            .tags(METRIC_CATEGORY, poolName)
            .register(meterRegistry);

    Gauge.builder(METRIC_NAME_LEASED_CONNECTIONS, poolStats, HttpPoolStats::getLeased)
            .description("Leased connections")
            .tags(METRIC_CATEGORY, poolName)
            .register(meterRegistry);

    Gauge.builder(METRIC_NAME_PENDING_CONNECTIONS, poolStats, HttpPoolStats::getPending)
            .description("Pending connections")
            .tags(METRIC_CATEGORY, poolName)
            .register(meterRegistry);

    Gauge.builder(METRIC_NAME_MAX_CONNECTIONS, poolStats, HttpPoolStats::getMax)
            .description("Max connections")
            .tags(METRIC_CATEGORY, poolName)
            .register(meterRegistry);
}

public void add(HttpRoute route, PoolingHttpClientConnectionManager poolingHttpClientConnectionManager) {
    String hostName = route.getTargetHost().getHostName();
    if (!poolStatsMap.containsKey(hostName)) {
        HttpPoolStats httpPoolStats = new HttpPoolStats(route, poolingHttpClientConnectionManager);
        poolStatsMap.put(hostName, httpPoolStats);
        createGauge(hostName, httpPoolStats, meterRegistry);
    }
}

}

@ravin-singh
Copy link
Author

public class HttpPoolStats {

private final HttpRoute httpRoute;
private final PoolingHttpClientConnectionManager poolingHttpClientConnectionManager;

public HttpPoolStats(HttpRoute httpRoute, PoolingHttpClientConnectionManager poolingHttpClientConnectionManager) {
    this.httpRoute = httpRoute;
    this.poolingHttpClientConnectionManager = poolingHttpClientConnectionManager;
}

public int getLeased() {
    return poolingHttpClientConnectionManager.getStats(httpRoute).getLeased();
}

public int getPending() {
    return poolingHttpClientConnectionManager.getStats(httpRoute).getPending();
}

public int getAvailable() {
    return poolingHttpClientConnectionManager.getStats(httpRoute).getAvailable();
}

public int getMax() {
    return poolingHttpClientConnectionManager.getStats(httpRoute).getMax();
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment