HDDS-16019. Publish httpfs gateway metrics to Prometheus via /prom endpoint - #10945
HDDS-16019. Publish httpfs gateway metrics to Prometheus via /prom endpoint#10945arunk-kumar wants to merge 3 commits into
Conversation
…dpoint Extract the Prometheus servlet wiring from BaseHttpServer into a public static helper (addPrometheusEndpoint) so HttpFSServerWebServer can expose /prom without extending BaseHttpServer. Wire the helper and the DefaultMetricsSystem lifecycle in HttpFSServerWebServer, gated by hdds.prometheus.endpoint.enabled.
Add httpfs:14000 to prometheus.yml scrape targets and add the httpfs service to the monitoring-config anchor in monitoring.yaml, enabling Prometheus to scrape the /prom endpoint added in the previous commit.
|
Verified end-to-end in the docker compose environment with 1. 2. Prometheus target health — httpfs scraped successfully: "scrapeUrl": "http://httpfs:14000/prom?user.name=hadoop",
"health": "up",
"lastError": "",
"lastScrape": "2026-08-04T08:05:03.987196928Z"3. httpfs {"__name__": "up", "component": "httpfs", "instance": "httpfs:14000", "job": "ozone-httpfs"} = 14. httpfs-specific metric queryable from Prometheus: {"__name__": "httpfsserver_bytes_read", "component": "httpfs", "instance": "httpfs:14000"} = 0Note on prometheus.yml: On acceptance tests: the existing |
chihsuan
left a comment
There was a problem hiding this comment.
Thanks for the patch! @arunk-kumar I left two inline comments, mainly around consistency and lifecycle handling. Otherwise, it works in the default setup 👍
| public void stop() throws Exception { | ||
| httpServer.stop(); | ||
| if (prometheusMetricsSink != null) { | ||
| DefaultMetricsSystem.instance().unregisterSource("prometheus"); |
There was a problem hiding this comment.
Would it make sense to omit this call? The Prometheus object is registered as a MetricsSink, while unregisterSource() only removes metrics sources, so it may not have any effect
| .build(); | ||
|
|
||
| if (conf.getBoolean(HddsConfigKeys.HDDS_PROMETHEUS_ENABLED, true)) { | ||
| prometheusMetricsSink = BaseHttpServer.addPrometheusEndpoint(httpServer, conf, NAME); |
There was a problem hiding this comment.
I found that with hdds.prometheus.endpoint.token set, httpfs rejects the bearer-token request that s3g accepts. Same token:
curl -H 'Authorization: Bearer testtoken' http://httpfs:14000/prom -> 401
curl -H 'Authorization: Bearer testtoken' http://s3g:19878/prom -> 200
Is this difference intentional, or should HttpFS be updated for consistency?
8b12a04 to
dc5ed5a
Compare
|
@chihsuan Thanks for the review! Issue 1 (unregisterSource): Fixed — removed the unregisterSource("prometheus") call from stop(). BaseHttpServer.stop() doesn't call it either; httpServer.stop() handles cleanup. Fix is in the latest commit. Issue 2 (bearer token vs S3G): You're right that the behavior differs. The root cause is that HttpFSAuthenticationFilter intercepts all requests (including /prom) before PrometheusServlet gets a chance to check the bearer token — unlike S3G which doesn't have that filter. This seems like a pre-existing inconsistency rather than something introduced by this PR. Happy to file a follow-up JIRA to track aligning the bearer token behavior across services, if that would be useful. |
What changes were proposed in this pull request?
HttpFSServerWebServer builds an HttpServer2 directly rather than extending BaseHttpServer, so it had no /prom endpoint and could not be scraped by Prometheus. This meant httpfs metrics were invisible to any Prometheus-based monitoring, and httpfs was absent from Grafana dashboards that group by component.
Changes:
Extract the Prometheus servlet wiring from BaseHttpServer into a new public static helper method addPrometheusEndpoint(HttpServer2, ConfigurationSource, String). This lives in the same package as BaseHttpServer so it retains access to the package-private PROMETHEUS_SINK constant and HttpServer2.getWebAppContext().
Refactor BaseHttpServer to call the helper — no behaviour change for existing services.
Wire the helper into HttpFSServerWebServer: call addPrometheusEndpoint in the constructor (after HttpServer2 is built), register the returned sink with DefaultMetricsSystem in start(), and unregister in stop(). Gated by hdds.prometheus.endpoint.enabled (default: true), matching the behaviour of other services.
The security model is preserved: if hdds.prometheus.endpoint.token is set, /prom is added as an internal servlet (token-based auth, SPNEGO bypassed); otherwise it is a regular servlet protected by the server's auth filter.
This is a prerequisite for HDDS-15858 (add httpfs to the ZDU Rolling Upgrade Grafana dashboard), which will add the httpfs scrape target and build-info metrics on top.
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-16019
Prereq for: HDDS-15858
Epic: HDDS-14496 (Zero Downtime Upgrade)
How was this patch tested?
Local verification against upstream/master:
mvn -pl :ozone-httpfsgateway,:hdds-server-framework -am install -DskipTests -DskipShade -DskipRecon -DskipDocs — builds clean.
mvn -pl :ozone-httpfsgateway,:hdds-server-framework checkstyle:check — 0 violations on both modules.
mvn -pl :ozone-httpfsgateway,:hdds-server-framework apache-rat:check — 0 unapproved licences.
mvn -pl :ozone-httpfsgateway,:hdds-server-framework test — 573 tests, 0 failures (1 pre-existing skip in TestNetworkTopologyImpl).
TestBaseHttpServer and TestPrometheusServletAuthorization in hdds-server-framework
pass without modification, confirming the refactor does not change existing behaviour.