summaryrefslogtreecommitdiffstats
path: root/metrics-proxy
diff options
context:
space:
mode:
authorOla Aunrønning <olaa@verizonmedia.com>2019-08-30 12:10:52 +0200
committerOla Aunrønning <olaa@verizonmedia.com>2019-08-30 12:10:52 +0200
commit6c658d24415dd5320edc5e8556f43a2d760d2173 (patch)
tree973ea72bfb2ae5a89680223d5b0221dc7dd09272 /metrics-proxy
parent94174f2b0d660d183041f22732cadd20b0655720 (diff)
parent7a5514c7918a0b18d5f7fd1906edc58b5310d4f0 (diff)
Merge branch 'gjoranv/prometheus-handler' of github.com:vespa-engine/vespa into metrics-proxy-gather-node-metrics
Diffstat (limited to 'metrics-proxy')
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/HttpHandlerBase.java90
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java33
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/RestApiUtil.java55
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandler.java36
4 files changed, 111 insertions, 103 deletions
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/HttpHandlerBase.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/HttpHandlerBase.java
new file mode 100644
index 00000000000..d582abdba57
--- /dev/null
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/HttpHandlerBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+ */
+
+package ai.vespa.metricsproxy.http;
+
+import ai.vespa.metricsproxy.core.MetricsConsumers;
+import ai.vespa.metricsproxy.core.MetricsManager;
+import ai.vespa.metricsproxy.service.VespaServices;
+import com.yahoo.container.jdisc.HttpRequest;
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.container.jdisc.ThreadedHttpRequestHandler;
+import com.yahoo.restapi.Path;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.Executor;
+
+import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR;
+import static com.yahoo.jdisc.Response.Status.METHOD_NOT_ALLOWED;
+import static com.yahoo.jdisc.Response.Status.NOT_FOUND;
+import static com.yahoo.jdisc.Response.Status.OK;
+import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
+import static java.util.logging.Level.WARNING;
+
+/**
+ * @author gjoranv
+ */
+public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler {
+
+ protected final ValuesFetcher valuesFetcher;
+
+ protected HttpHandlerBase(Executor executor,
+ MetricsManager metricsManager,
+ VespaServices vespaServices,
+ MetricsConsumers metricsConsumers) {
+ super(executor);
+ valuesFetcher = new ValuesFetcher(metricsManager, vespaServices, metricsConsumers);
+ }
+
+ protected abstract Optional<HttpResponse> doHandle(URI requestUri, Path apiPath, String consumer);
+
+ @Override
+ public final HttpResponse handle(HttpRequest request) {
+ if (request.getMethod() != GET) return new JsonResponse(METHOD_NOT_ALLOWED, "Only GET is supported");
+
+ Path path = new Path(request.getUri());
+
+ return doHandle(request.getUri(), path, getConsumer(request))
+ .orElse(new ErrorResponse(NOT_FOUND, "No content at given path"));
+ }
+
+ private String getConsumer(HttpRequest request) {
+ return request.getProperty("consumer");
+ }
+
+ protected JsonResponse resourceListResponse(URI requestUri, List<String> resources) {
+ try {
+ return new JsonResponse(OK, resourceList(requestUri, resources));
+ } catch (JSONException e) {
+ log.log(WARNING, "Bad JSON construction in generated resource list for " + requestUri.getPath(), e);
+ return new ErrorResponse(INTERNAL_SERVER_ERROR,
+ "An error occurred when generating the list of api resources.");
+ }
+ }
+
+ // TODO: Use jackson with a "Resources" class instead of JSONObject
+ private static String resourceList(URI requestUri, List<String> resources) throws JSONException {
+ int port = requestUri.getPort();
+ String host = requestUri.getHost();
+ StringBuilder base = new StringBuilder("http://");
+ base.append(host);
+ if (port >= 0) {
+ base.append(":").append(port);
+ }
+ String uriBase = base.toString();
+ JSONArray linkList = new JSONArray();
+ for (String api : resources) {
+ JSONObject resource = new JSONObject();
+ resource.put("url", uriBase + api);
+ linkList.put(resource);
+ }
+ return new JSONObject().put("resources", linkList).toString(4);
+ }
+
+}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java
index 1eb3429f6d4..1f163dc6b9a 100644
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java
@@ -10,59 +10,46 @@ import ai.vespa.metricsproxy.metric.model.MetricsPacket;
import ai.vespa.metricsproxy.metric.model.json.JsonRenderingException;
import ai.vespa.metricsproxy.service.VespaServices;
import com.google.inject.Inject;
-import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
-import com.yahoo.container.jdisc.ThreadedHttpRequestHandler;
import com.yahoo.restapi.Path;
+import java.net.URI;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
-import static ai.vespa.metricsproxy.http.RestApiUtil.resourceListResponse;
import static ai.vespa.metricsproxy.metric.model.json.GenericJsonUtil.toGenericJsonModel;
import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR;
-import static com.yahoo.jdisc.Response.Status.METHOD_NOT_ALLOWED;
-import static com.yahoo.jdisc.Response.Status.NOT_FOUND;
import static com.yahoo.jdisc.Response.Status.OK;
-import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
/**
* Http handler for the metrics/v1 rest api.
*
* @author gjoranv
*/
-public class MetricsHandler extends ThreadedHttpRequestHandler {
+public class MetricsHandler extends HttpHandlerBase {
public static final String V1_PATH = "/metrics/v1";
static final String VALUES_PATH = V1_PATH + "/values";
- private final ValuesFetcher valuesFetcher;
-
@Inject
public MetricsHandler(Executor executor,
MetricsManager metricsManager,
VespaServices vespaServices,
MetricsConsumers metricsConsumers) {
- super(executor);
-
- valuesFetcher = new ValuesFetcher(metricsManager, vespaServices, metricsConsumers);
+ super(executor, metricsManager, vespaServices, metricsConsumers);
}
@Override
- public HttpResponse handle(HttpRequest request) {
- if (request.getMethod() != GET) return new JsonResponse(METHOD_NOT_ALLOWED, "Only GET is supported");
-
- Path path = new Path(request.getUri());
-
- if (path.matches(V1_PATH)) return resourceListResponse(request.getUri(), List.of(VALUES_PATH));
- if (path.matches(VALUES_PATH)) return valuesResponse(request);
-
- return new ErrorResponse(NOT_FOUND, "No content at given path");
+ public Optional<HttpResponse> doHandle(URI requestUri, Path apiPath, String consumer) {
+ if (apiPath.matches(V1_PATH)) return Optional.of(resourceListResponse(requestUri, List.of(VALUES_PATH)));
+ if (apiPath.matches(VALUES_PATH)) return Optional.of(valuesResponse(consumer));
+ return Optional.empty();
}
- private JsonResponse valuesResponse(HttpRequest request) {
+ private JsonResponse valuesResponse(String consumer) {
try {
- List<MetricsPacket> metrics = valuesFetcher.fetch(request.getProperty("consumer"));
+ List<MetricsPacket> metrics = valuesFetcher.fetch(consumer);
return new JsonResponse(OK, toGenericJsonModel(metrics).serialize());
} catch (JsonRenderingException e) {
return new ErrorResponse(INTERNAL_SERVER_ERROR, e.getMessage());
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/RestApiUtil.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/RestApiUtil.java
deleted file mode 100644
index 9d9256e17e8..00000000000
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/RestApiUtil.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
- */
-
-package ai.vespa.metricsproxy.http;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.net.URI;
-import java.util.List;
-import java.util.logging.Logger;
-
-import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR;
-import static com.yahoo.jdisc.Response.Status.OK;
-import static java.util.logging.Level.WARNING;
-
-/**
- * @author gjoranv
- */
-public class RestApiUtil {
- private static Logger log = Logger.getLogger(RestApiUtil.class.getName());
-
-
- public static JsonResponse resourceListResponse(URI requestUri, List<String> resources) {
- try {
- return new JsonResponse(OK, RestApiUtil.resourceList(requestUri, resources));
- } catch (JSONException e) {
- log.log(WARNING, "Bad JSON construction in generated resource list for " + requestUri.getPath(), e);
- return new ErrorResponse(INTERNAL_SERVER_ERROR,
- "An error occurred when generating the list of api resources.");
- }
- }
-
- // TODO: Use jackson with a "Resources" class instead of JSONObject
- private static String resourceList(URI requestUri, List<String> resources) throws JSONException {
- int port = requestUri.getPort();
- String host = requestUri.getHost();
- StringBuilder base = new StringBuilder("http://");
- base.append(host);
- if (port >= 0) {
- base.append(":").append(port);
- }
- String uriBase = base.toString();
- JSONArray linkList = new JSONArray();
- for (String api : resources) {
- JSONObject resource = new JSONObject();
- resource.put("url", uriBase + api);
- linkList.put(resource);
- }
- return new JSONObject().put("resources", linkList).toString(4);
- }
-
-}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandler.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandler.java
index f2009280128..02f11c7e900 100644
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandler.java
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandler.java
@@ -6,64 +6,50 @@ package ai.vespa.metricsproxy.http.prometheus;
import ai.vespa.metricsproxy.core.MetricsConsumers;
import ai.vespa.metricsproxy.core.MetricsManager;
-import ai.vespa.metricsproxy.http.ErrorResponse;
-import ai.vespa.metricsproxy.http.JsonResponse;
+import ai.vespa.metricsproxy.http.HttpHandlerBase;
import ai.vespa.metricsproxy.http.TextResponse;
-import ai.vespa.metricsproxy.http.ValuesFetcher;
import ai.vespa.metricsproxy.metric.model.MetricsPacket;
import ai.vespa.metricsproxy.metric.model.json.JsonRenderingException;
import ai.vespa.metricsproxy.service.VespaServices;
import com.google.inject.Inject;
-import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
-import com.yahoo.container.jdisc.ThreadedHttpRequestHandler;
import com.yahoo.restapi.Path;
+import java.net.URI;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
-import static ai.vespa.metricsproxy.http.RestApiUtil.resourceListResponse;
import static ai.vespa.metricsproxy.metric.model.prometheus.PrometheusUtil.toPrometheusModel;
import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR;
-import static com.yahoo.jdisc.Response.Status.METHOD_NOT_ALLOWED;
-import static com.yahoo.jdisc.Response.Status.NOT_FOUND;
import static com.yahoo.jdisc.Response.Status.OK;
-import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
/**
* @author gjoranv
*/
-public class PrometheusHandler extends ThreadedHttpRequestHandler {
+public class PrometheusHandler extends HttpHandlerBase {
public static final String V1_PATH = "/prometheus/v1";
static final String VALUES_PATH = V1_PATH + "/values";
- private final ValuesFetcher valuesFetcher;
-
@Inject
public PrometheusHandler(Executor executor,
MetricsManager metricsManager,
VespaServices vespaServices,
MetricsConsumers metricsConsumers) {
- super(executor);
- valuesFetcher = new ValuesFetcher(metricsManager, vespaServices, metricsConsumers);
+ super(executor, metricsManager, vespaServices, metricsConsumers);
}
@Override
- public HttpResponse handle(HttpRequest request) {
- if (request.getMethod() != GET) return new JsonResponse(METHOD_NOT_ALLOWED, "Only GET is supported");
-
- Path path = new Path(request.getUri());
-
- if (path.matches(V1_PATH)) return resourceListResponse(request.getUri(), List.of(VALUES_PATH));
- if (path.matches(VALUES_PATH)) return valuesResponse(request);
-
- return new ErrorResponse(NOT_FOUND, "No content at given path");
+ public Optional<HttpResponse> doHandle(URI requestUri, Path apiPath, String consumer) {
+ if (apiPath.matches(V1_PATH)) return Optional.of(resourceListResponse(requestUri, List.of(VALUES_PATH)));
+ if (apiPath.matches(VALUES_PATH)) return Optional.of(valuesResponse(consumer));
+ return Optional.empty();
}
- private TextResponse valuesResponse(HttpRequest request) {
+ private TextResponse valuesResponse(String consumer) {
try {
- List<MetricsPacket> metrics = valuesFetcher.fetch(request.getProperty("consumer"));
+ List<MetricsPacket> metrics = valuesFetcher.fetch(consumer);
return new TextResponse(OK, toPrometheusModel(metrics).serialize());
} catch (JsonRenderingException e) {
return new TextResponse(INTERNAL_SERVER_ERROR, e.getMessage());