Skip to content

Commit dfa2356

Browse files
committed
feat: Add metricsHandlerPath and registerHealthHandler configuration options to HTTPServer
Signed-off-by: David Sondermann <[email protected]>
1 parent 975e7c0 commit dfa2356

File tree

3 files changed

+94
-17
lines changed

3 files changed

+94
-17
lines changed

prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/DefaultHandler.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,27 @@ public class DefaultHandler implements HttpHandler {
1111
private final byte[] responseBytes;
1212
private final String contentType;
1313

14-
public DefaultHandler() {
14+
public DefaultHandler(String metricsPath) {
15+
String metrics = metricsPath.startsWith("/") ? metricsPath.substring(1) : metricsPath;
1516
String responseString =
1617
"<html>\n"
1718
+ "<head><title>Prometheus Java Client</title></head>\n"
1819
+ "<body>\n"
1920
+ "<h1>Prometheus Java Client</h1>\n"
2021
+ "<h2>Metrics Path</h2>\n"
21-
+ "The metrics path is <a href=\"metrics\">/metrics</a>.\n"
22+
+ String.format("The metrics path is <a href=\"%s\">%s</a>.\n", metrics, metricsPath)
2223
+ "<h2>Name Filter</h2>\n"
2324
+ "If you want to scrape only specific metrics, "
2425
+ "use the <tt>name[]</tt> parameter like this:\n"
2526
+ "<ul>\n"
26-
+ "<li><a href=\"metrics?name[]=my_metric\">/metrics?name[]=my_metric</a></li>\n"
27+
+ String.format(
28+
"<li><a href=\"%s?name[]=my_metric\">%s?name[]=my_metric</a></li>\n",
29+
metrics, metricsPath)
2730
+ "</ul>\n"
2831
+ "You can also use multiple <tt>name[]</tt> parameters to query multiple metrics:\n"
2932
+ "<ul>\n"
30-
+ "<li><a href=\"metrics?name[]=my_metric_a&name=my_metrics_b\">"
31-
+ "/metrics?name[]=my_metric_a&amp;name=[]=my_metric_b</a></li>\n"
33+
+ String.format("<li><a href=\"%s?name[]=my_metric_a&name[]=my_metric_b\">", metrics)
34+
+ String.format("%s?name[]=my_metric_a&amp;name[]=my_metric_b</a></li>\n", metricsPath)
3235
+ "</ul>\n"
3336
+ "The <tt>name[]</tt> parameter can be used by the Prometheus server for scraping. "
3437
+ "Add the following snippet to your scrape job configuration in "
@@ -50,13 +53,17 @@ public DefaultHandler() {
5053
+ "The Prometheus Java metrics library supports a <tt>debug</tt> query parameter "
5154
+ "for viewing the different formats in a Web browser:\n"
5255
+ "<ul>\n"
53-
+ "<li><a href=\"metrics?debug=openmetrics\">/metrics?debug=openmetrics</a>: "
56+
+ String.format(
57+
"<li><a href=\"%s?debug=openmetrics\">%s?debug=openmetrics</a>: ",
58+
metrics, metricsPath)
5459
+ "View OpenMetrics text format.</li>\n"
55-
+ "<li><a href=\"metrics?debug=text\">/metrics?debug=text</a>: "
60+
+ String.format(
61+
"<li><a href=\"%s?debug=text\">%s?debug=text</a>: ", metrics, metricsPath)
5662
+ "View Prometheus text format (this is the default when accessing the "
57-
+ "<a href=\"metrics\">/metrics</a> endpoint with a Web browser).</li>\n"
58-
+ "<li><a href=\"metrics?debug=prometheus-protobuf\">"
59-
+ "/metrics?debug=prometheus-protobuf</a>: "
63+
+ String.format(
64+
"<a href=\"%s\">%s</a> endpoint with a Web browser).</li>\n", metrics, metricsPath)
65+
+ String.format("<li><a href=\"%s?debug=prometheus-protobuf\">", metrics)
66+
+ String.format("%s?debug=prometheus-protobuf</a>: ", metricsPath)
6067
+ "View a text representation of the Prometheus protobuf format.</li>\n"
6168
+ "</ul>\n"
6269
+ "Note that the <tt>debug</tt> parameter is only for viewing different formats in a "

prometheus-metrics-exporter-httpserver/src/main/java/io/prometheus/metrics/exporter/httpserver/HTTPServer.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,24 +57,29 @@ private HTTPServer(
5757
PrometheusRegistry registry,
5858
@Nullable Authenticator authenticator,
5959
@Nullable String authenticatedSubjectAttributeName,
60-
@Nullable HttpHandler defaultHandler) {
60+
@Nullable HttpHandler defaultHandler,
61+
@Nullable String metricsHandlerPath,
62+
@Nullable Boolean registerHealthHandler) {
6163
if (httpServer.getAddress() == null) {
6264
throw new IllegalArgumentException("HttpServer hasn't been bound to an address");
6365
}
6466
this.server = httpServer;
6567
this.executorService = executorService;
68+
String metricsPath = getMetricsPath(metricsHandlerPath);
6669
registerHandler(
6770
"/",
68-
defaultHandler == null ? new DefaultHandler() : defaultHandler,
71+
defaultHandler == null ? new DefaultHandler(metricsPath) : defaultHandler,
6972
authenticator,
7073
authenticatedSubjectAttributeName);
7174
registerHandler(
72-
"/metrics",
75+
metricsPath,
7376
new MetricsHandler(config, registry),
7477
authenticator,
7578
authenticatedSubjectAttributeName);
76-
registerHandler(
77-
"/-/healthy", new HealthyHandler(), authenticator, authenticatedSubjectAttributeName);
79+
if (registerHealthHandler == null || registerHealthHandler) {
80+
registerHandler(
81+
"/-/healthy", new HealthyHandler(), authenticator, authenticatedSubjectAttributeName);
82+
}
7883
try {
7984
// HttpServer.start() starts the HttpServer in a new background thread.
8085
// If we call HttpServer.start() from a thread of the executorService,
@@ -88,6 +93,16 @@ private HTTPServer(
8893
}
8994
}
9095

96+
private String getMetricsPath(@Nullable String metricsHandlerPath) {
97+
if (metricsHandlerPath == null) {
98+
return "/metrics";
99+
}
100+
if (!metricsHandlerPath.startsWith("/")) {
101+
return "/" + metricsHandlerPath;
102+
}
103+
return metricsHandlerPath;
104+
}
105+
91106
private void registerHandler(
92107
String path,
93108
HttpHandler handler,
@@ -179,9 +194,11 @@ public static class Builder {
179194
@Nullable private ExecutorService executorService = null;
180195
@Nullable private PrometheusRegistry registry = null;
181196
@Nullable private Authenticator authenticator = null;
197+
@Nullable private String authenticatedSubjectAttributeName = null;
182198
@Nullable private HttpsConfigurator httpsConfigurator = null;
183199
@Nullable private HttpHandler defaultHandler = null;
184-
@Nullable private String authenticatedSubjectAttributeName = null;
200+
@Nullable private String metricsHandlerPath = null;
201+
@Nullable private Boolean registerHealthHandler = null;
185202

186203
private Builder(PrometheusProperties config) {
187204
this.config = config;
@@ -254,6 +271,18 @@ public Builder defaultHandler(HttpHandler defaultHandler) {
254271
return this;
255272
}
256273

274+
/** Optional: Override default path for the metrics endpoint. Default is {@code /metrics}. */
275+
public Builder metricsHandlerPath(String metricsHandlerPath) {
276+
this.metricsHandlerPath = metricsHandlerPath;
277+
return this;
278+
}
279+
280+
/** Optional: Override if the health handler should be registered. Default is {@code true}. */
281+
public Builder registerHealthHandler(boolean registerHealthHandler) {
282+
this.registerHealthHandler = registerHealthHandler;
283+
return this;
284+
}
285+
257286
/** Build and start the HTTPServer. */
258287
public HTTPServer buildAndStart() throws IOException {
259288
if (registry == null) {
@@ -275,7 +304,9 @@ public HTTPServer buildAndStart() throws IOException {
275304
registry,
276305
authenticator,
277306
authenticatedSubjectAttributeName,
278-
defaultHandler);
307+
defaultHandler,
308+
metricsHandlerPath,
309+
registerHealthHandler);
279310
}
280311

281312
private InetSocketAddress makeInetSocketAddress() {

prometheus-metrics-exporter-httpserver/src/test/java/io/prometheus/metrics/exporter/httpserver/HTTPServerTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ void metrics() throws IOException {
105105
"/metrics");
106106
}
107107

108+
@Test
109+
void metricsCustomPath() throws IOException {
110+
run(
111+
HTTPServer.builder()
112+
.port(0)
113+
.registry(new PrometheusRegistry())
114+
.metricsHandlerPath("/my-metrics")
115+
.executorService(Executors.newFixedThreadPool(1))
116+
.buildAndStart(),
117+
"200",
118+
"/my-metrics");
119+
}
120+
108121
@Test
109122
void registryThrows() throws IOException {
110123
HTTPServer server =
@@ -147,4 +160,30 @@ void config() throws NoSuchAlgorithmException, IOException {
147160
void health() throws IOException {
148161
run(HTTPServer.builder().port(0).buildAndStart(), "200", "/-/healthy");
149162
}
163+
164+
@Test
165+
void healthEnabled() throws IOException {
166+
HttpHandler handler = exchange -> exchange.sendResponseHeaders(204, -1);
167+
run(
168+
HTTPServer.builder()
169+
.port(0)
170+
.defaultHandler(handler)
171+
.registerHealthHandler(true)
172+
.buildAndStart(),
173+
"200",
174+
"/-/healthy");
175+
}
176+
177+
@Test
178+
void healthDisabled() throws IOException {
179+
HttpHandler handler = exchange -> exchange.sendResponseHeaders(204, -1);
180+
run(
181+
HTTPServer.builder()
182+
.port(0)
183+
.defaultHandler(handler)
184+
.registerHealthHandler(false)
185+
.buildAndStart(),
186+
"204",
187+
"/-/healthy");
188+
}
150189
}

0 commit comments

Comments
 (0)