Merge pull request #110 from overleaf/spd-prom-metrics-handler

Export prometheus metrics directly from handler
This commit is contained in:
Simon Detheridge 2021-06-22 16:48:49 +01:00 committed by GitHub
commit 830b7f54fc

View file

@ -1,6 +1,7 @@
package uk.ac.ic.wlgitbridge.server; package uk.ac.ic.wlgitbridge.server;
import io.prometheus.client.exporter.MetricsServlet; import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.common.TextFormat;
import io.prometheus.client.hotspot.DefaultExports; import io.prometheus.client.hotspot.DefaultExports;
import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.HttpConnection;
@ -15,33 +16,18 @@ import uk.ac.ic.wlgitbridge.util.Log;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
/** import java.util.HashSet;
* Wrapper for the MetricsServlet from the Prometheus client. import java.util.Set;
*
* We wrap this in a handler here, as we use a wildcard servlet context on /*, and adding
* an additional servlet context collides with it. Adding a servlet context on /metrics
* causes a redirect to /metrics/ which breaks things when jetty doesn't know the full
* public URL.
*
* There may still be a better way to do this, but it works.
**/
public class PrometheusHandler extends AbstractHandler { public class PrometheusHandler extends AbstractHandler {
private final ServletHolder holder;
public PrometheusHandler() { public PrometheusHandler() {
DefaultExports.initialize(); DefaultExports.initialize();
this.holder = new ServletHolder(new MetricsServlet());
try {
this.holder.initialize();
} catch (Exception e) {
Log.error("Unable to initialise metrics servlet: " + e.getMessage());
}
} }
@Override @Override
@ -58,20 +44,35 @@ public class PrometheusHandler extends AbstractHandler {
&& target.matches("^/metrics/?$") && target.matches("^/metrics/?$")
) { ) {
Log.info(method + " <- /metrics"); Log.info(method + " <- /metrics");
this.printMetrics(request, response);
baseRequest.setHandled(true);
}
}
private void printMetrics(
HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException {
response.setStatus(200);
String contentType = TextFormat.chooseContentType(request.getHeader("Accept"));
response.setContentType(contentType);
Writer writer = new BufferedWriter(response.getWriter());
if (!this.holder.isAvailable()) {
try { try {
this.holder.start(); TextFormat.writeFormat(contentType, writer, CollectorRegistry.defaultRegistry.filteredMetricFamilySamples(parse(request)));
} catch (Exception e) { writer.flush();
Log.error("Unable to start metrics servlet: " + e.getMessage()); } finally {
response.setStatus(500); writer.close();
baseRequest.setHandled(true);
return;
} }
} }
this.holder.handle(baseRequest, request, response); private Set<String> parse(HttpServletRequest req) {
baseRequest.setHandled(true); String[] includedParam = req.getParameterValues("name[]");
if (includedParam == null) {
return Collections.emptySet();
} else {
return new HashSet<String>(Arrays.asList(includedParam));
} }
} }
} }