aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgjoranv <gv@verizonmedia.com>2019-07-08 10:21:43 +0200
committergjoranv <gv@verizonmedia.com>2019-07-09 11:22:56 +0200
commit447357bd91208cb3d672850412e11d7bfc8ba009 (patch)
treee305a638516606de1b0e501c98546391314681ba
parent262be1a425e21e4f5c149f1d3162f4fdaed372e7 (diff)
Implement the /metrics/v1 rest api.
- Json errors are now handled in ErrorResponse instead of JsonRenderingException
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java4
-rw-r--r--metrics-proxy/pom.xml12
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ErrorResponse.java33
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/GenericMetricsHandler.java100
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/JsonResponse.java33
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java99
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ValuesFetcher.java65
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingException.java30
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/ErrorResponseTest.java (renamed from metrics-proxy/src/test/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingExceptionTest.java)13
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/MetricsHandlerTest.java (renamed from metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/GenericMetricsHandlerTest.java)43
11 files changed, 281 insertions, 159 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
index f290911c6bd..1b30faa3e21 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
@@ -9,7 +9,7 @@ import ai.vespa.metricsproxy.core.MetricsConsumers;
import ai.vespa.metricsproxy.core.MetricsManager;
import ai.vespa.metricsproxy.core.MonitoringConfig;
import ai.vespa.metricsproxy.core.VespaMetrics;
-import ai.vespa.metricsproxy.http.GenericMetricsHandler;
+import ai.vespa.metricsproxy.http.MetricsHandler;
import ai.vespa.metricsproxy.metric.ExternalMetrics;
import ai.vespa.metricsproxy.metric.dimensions.ApplicationDimensions;
import ai.vespa.metricsproxy.metric.dimensions.ApplicationDimensionsConfig;
@@ -49,8 +49,8 @@ import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerClus
import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.TENANT;
import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.ZONE;
import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicConsumer.getDefaultPublicConsumer;
-import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.getVespaMetricsConsumer;
import static com.yahoo.vespa.model.admin.monitoring.MetricSet.emptyMetricSet;
+import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.getVespaMetricsConsumer;
import static com.yahoo.vespa.model.container.xml.BundleMapper.JarSuffix.JAR_WITH_DEPS;
import static com.yahoo.vespa.model.container.xml.BundleMapper.absoluteBundlePath;
@@ -71,7 +71,7 @@ public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyC
static final Path METRICS_PROXY_BUNDLE_FILE = absoluteBundlePath((Paths.get(METRICS_PROXY_NAME + JAR_WITH_DEPS.suffix)));
static final String METRICS_PROXY_BUNDLE_NAME = "com.yahoo.vespa." + METRICS_PROXY_NAME;
- private static final String METRICS_HANDLER_BINDING = "/metrics/v1/values";
+ private static final String METRICS_HANDLER_BINDING = "/metrics/v1/*";
static final class AppDimensionNames {
static final String ZONE = "zone";
@@ -113,7 +113,7 @@ public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyC
private void addGenericMetricsHandler() {
Handler<AbstractConfigProducer<?>> metricsHandler = new Handler<>(
- new ComponentModel(GenericMetricsHandler.class.getName(), null, METRICS_PROXY_BUNDLE_NAME, null));
+ new ComponentModel(MetricsHandler.class.getName(), null, METRICS_PROXY_BUNDLE_NAME, null));
metricsHandler.addServerBindings("http://*" + METRICS_HANDLER_BINDING,
"http://*" + METRICS_HANDLER_BINDING + "/*");
addComponent(metricsHandler);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java
index fbd1c7455dd..9c75b80c2f4 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java
@@ -4,7 +4,7 @@
package com.yahoo.vespa.model.admin.monitoring;
-import ai.vespa.metricsproxy.http.GenericMetricsHandler;
+import ai.vespa.metricsproxy.http.ValuesFetcher;
import com.google.common.collect.ImmutableList;
import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicMetrics.defaultPublicMetricSet;
@@ -17,7 +17,7 @@ import static java.util.Collections.emptyList;
*/
public class DefaultPublicConsumer {
- public static final String DEFAULT_PUBLIC_CONSUMER_ID = GenericMetricsHandler.DEFAULT_PUBLIC_CONSUMER_ID.id;
+ public static final String DEFAULT_PUBLIC_CONSUMER_ID = ValuesFetcher.DEFAULT_PUBLIC_CONSUMER_ID.id;
private static final MetricSet publicConsumerMetrics = new MetricSet("public-consumer-metrics",
emptyList(),
diff --git a/metrics-proxy/pom.xml b/metrics-proxy/pom.xml
index 3cfe1d2f568..26caa3f66af 100644
--- a/metrics-proxy/pom.xml
+++ b/metrics-proxy/pom.xml
@@ -79,6 +79,12 @@
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
+ <artifactId>jdisc_http_service</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
<artifactId>jrt</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
@@ -110,12 +116,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>com.yahoo.vespa</groupId>
- <artifactId>jdisc_http_service</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ErrorResponse.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ErrorResponse.java
new file mode 100644
index 00000000000..679bae84f8e
--- /dev/null
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ErrorResponse.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import static java.util.logging.Level.WARNING;
+
+/**
+ * @author gjoranv
+ */
+class ErrorResponse extends JsonResponse {
+ private static Logger log = Logger.getLogger(ErrorResponse.class.getName());
+
+ ErrorResponse(int code, String message) {
+ super(code, asErrorJson(message));
+ }
+
+ static String asErrorJson(String message) {
+ try {
+ return new ObjectMapper().writeValueAsString(Map.of("error", message));
+ } catch (JsonProcessingException e) {
+ log.log(WARNING, "Could not encode error message to json:", e);
+ return "Could not encode error message to json, check the log for details.";
+ }
+ }
+}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/GenericMetricsHandler.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/GenericMetricsHandler.java
deleted file mode 100644
index f61a96917a9..00000000000
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/GenericMetricsHandler.java
+++ /dev/null
@@ -1,100 +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 ai.vespa.metricsproxy.core.MetricsConsumers;
-import ai.vespa.metricsproxy.core.MetricsManager;
-import ai.vespa.metricsproxy.metric.model.ConsumerId;
-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 java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.time.Instant;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-import static ai.vespa.metricsproxy.metric.model.ConsumerId.toConsumerId;
-import static ai.vespa.metricsproxy.metric.model.json.GenericJsonUtil.toGenericJsonModel;
-
-/**
- * Http handler that exposes the generic metrics format.
- *
- * @author gjoranv
- */
-public class GenericMetricsHandler extends ThreadedHttpRequestHandler {
- private static final Logger log = Logger.getLogger(GenericMetricsHandler.class.getName());
-
- public static final ConsumerId DEFAULT_PUBLIC_CONSUMER_ID = toConsumerId("default");
-
- private final MetricsConsumers metricsConsumers;
- private final MetricsManager metricsManager;
- private final VespaServices vespaServices;
-
- @Inject
- public GenericMetricsHandler(Executor executor,
- MetricsManager metricsManager,
- VespaServices vespaServices,
- MetricsConsumers metricsConsumers) {
- super(executor);
- this.metricsConsumers = metricsConsumers;
- this.metricsManager = metricsManager;
- this.vespaServices = vespaServices;
- }
-
- @Override
- public HttpResponse handle(HttpRequest request) {
- try {
- ConsumerId consumer = getConsumerOrDefault(request.getProperty("consumer"));
-
- List<MetricsPacket> metrics = metricsManager.getMetrics(vespaServices.getVespaServices(), Instant.now())
- .stream()
- .filter(metricsPacket -> metricsPacket.consumers().contains(consumer))
- .collect(Collectors.toList());
- return new Response(200, toGenericJsonModel(metrics).serialize());
- } catch (JsonRenderingException e) {
- return new Response(500, e.getMessageAsJson());
- }
- }
-
- private ConsumerId getConsumerOrDefault(String consumer) {
- if (consumer == null) return DEFAULT_PUBLIC_CONSUMER_ID;
-
- ConsumerId consumerId = toConsumerId(consumer);
- if (! metricsConsumers.getAllConsumers().contains(consumerId)) {
- log.info("No consumer with id '" + consumer + "' - using the default consumer instead.");
- return DEFAULT_PUBLIC_CONSUMER_ID;
- }
- return consumerId;
- }
-
- private static class Response extends HttpResponse {
- private final byte[] data;
-
- Response(int code, String data) {
- super(code);
- this.data = data.getBytes(Charset.forName(DEFAULT_CHARACTER_ENCODING));
- }
-
- @Override
- public String getContentType() {
- return "application/json";
- }
-
- @Override
- public void render(OutputStream outputStream) throws IOException {
- outputStream.write(data);
- }
- }
-
-}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/JsonResponse.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/JsonResponse.java
new file mode 100644
index 00000000000..758a043a823
--- /dev/null
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/JsonResponse.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.yahoo.container.jdisc.HttpResponse;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+
+/**
+ * @author gjoranv
+ */
+class JsonResponse extends HttpResponse {
+ private final byte[] data;
+
+ JsonResponse(int code, String data) {
+ super(code);
+ this.data = data.getBytes(Charset.forName(DEFAULT_CHARACTER_ENCODING));
+ }
+
+ @Override
+ public String getContentType() {
+ return "application/json";
+ }
+
+ @Override
+ public void render(OutputStream outputStream) throws IOException {
+ outputStream.write(data);
+ }
+}
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
new file mode 100644
index 00000000000..1d7206f177d
--- /dev/null
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/MetricsHandler.java
@@ -0,0 +1,99 @@
+/*
+ * 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.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 org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URI;
+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;
+
+/**
+ * Http handler for the metrics/v1 rest api.
+ *
+ * @author gjoranv
+ */
+public class MetricsHandler extends ThreadedHttpRequestHandler {
+
+ 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);
+ }
+
+ @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 v1Response(request.getUri());
+ if (path.matches(VALUES_PATH)) return valuesResponse(request);
+
+ return new ErrorResponse(NOT_FOUND, "No content at given path");
+ }
+
+ private JsonResponse v1Response(URI requestUri) {
+ try {
+ return new JsonResponse(OK, v1Content(requestUri));
+ } catch (JSONException e) {
+ log.warning("Bad JSON construction in " + V1_PATH + " response: " + e.getMessage());
+ return new ErrorResponse(INTERNAL_SERVER_ERROR,
+ "An error occurred, please try path '" + VALUES_PATH + "'");
+ }
+ }
+
+ private JsonResponse valuesResponse(HttpRequest request) {
+ try {
+ return new JsonResponse(OK, valuesFetcher.fetch(request.getProperty("consumer")));
+ } catch (JsonRenderingException e) {
+ return new ErrorResponse(INTERNAL_SERVER_ERROR, e.getMessage());
+ }
+ }
+
+ // TODO: Use jackson with a "Resources" class instead of JSONObject
+ private String v1Content(URI requestUri) 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 : new String[] {VALUES_PATH}) {
+ 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/ValuesFetcher.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ValuesFetcher.java
new file mode 100644
index 00000000000..4686d9c1751
--- /dev/null
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/http/ValuesFetcher.java
@@ -0,0 +1,65 @@
+/*
+ * 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.metric.model.ConsumerId;
+import ai.vespa.metricsproxy.metric.model.MetricsPacket;
+import ai.vespa.metricsproxy.metric.model.json.JsonRenderingException;
+import ai.vespa.metricsproxy.service.VespaServices;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import static ai.vespa.metricsproxy.metric.model.ConsumerId.toConsumerId;
+import static ai.vespa.metricsproxy.metric.model.json.GenericJsonUtil.toGenericJsonModel;
+
+/**
+ * Generates metrics values in json format for the metrics/v1 rest api.
+ *
+ * @author gjoranv
+ */
+public class ValuesFetcher {
+ private static final Logger log = Logger.getLogger(ValuesFetcher.class.getName());
+
+ public static final ConsumerId DEFAULT_PUBLIC_CONSUMER_ID = toConsumerId("default");
+
+ private final MetricsManager metricsManager;
+ private final VespaServices vespaServices;
+ private final MetricsConsumers metricsConsumers;
+
+ ValuesFetcher(MetricsManager metricsManager,
+ VespaServices vespaServices,
+ MetricsConsumers metricsConsumers) {
+ this.metricsManager = metricsManager;
+ this.vespaServices = vespaServices;
+ this.metricsConsumers = metricsConsumers;
+ }
+
+ public String fetch(String requestedConsumer) throws JsonRenderingException {
+ ConsumerId consumer = getConsumerOrDefault(requestedConsumer);
+
+ List<MetricsPacket> metrics = metricsManager.getMetrics(vespaServices.getVespaServices(), Instant.now())
+ .stream()
+ .filter(metricsPacket -> metricsPacket.consumers().contains(consumer))
+ .collect(Collectors.toList());
+ return toGenericJsonModel(metrics).serialize();
+ }
+
+ private ConsumerId getConsumerOrDefault(String consumer) {
+ if (consumer == null) return DEFAULT_PUBLIC_CONSUMER_ID;
+
+ ConsumerId consumerId = toConsumerId(consumer);
+ if (! metricsConsumers.getAllConsumers().contains(consumerId)) {
+ log.info("No consumer with id '" + consumer + "' - using the default consumer instead.");
+ return DEFAULT_PUBLIC_CONSUMER_ID;
+ }
+ return consumerId;
+ }
+
+}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingException.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingException.java
index 4c1d42d75ee..02292cea164 100644
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingException.java
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingException.java
@@ -4,43 +4,15 @@
package ai.vespa.metricsproxy.metric.model.json;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import java.util.Map;
-import java.util.logging.Logger;
-
-import static java.util.logging.Level.WARNING;
-
/**
- * An exception to be thrown upon errors in json rendering, and that can deliver its message wrapped
- * in an "error" json object.
+ * An unchecked exception to be thrown upon errors in json rendering.
*
* @author gjoranv
*/
public class JsonRenderingException extends RuntimeException {
- private static Logger log = Logger.getLogger(JsonRenderingException.class.getName());
-
JsonRenderingException(String message) {
super(message);
}
- /**
- * Returns the message wrapped in an "error" json object. In the unlikely case that json rendering of the
- * error message fails, a plain text string will be returned instead.
- */
- public String getMessageAsJson() {
- return wrap(getMessage());
- }
-
- private static String wrap(String message) {
- try {
- return new ObjectMapper().writeValueAsString(Map.of("error", message));
- } catch (JsonProcessingException e) {
- log.log(WARNING, "Could not encode error message to json:", e);
- return "Could not encode error message to json, check the log for details.";
- }
- }
-
}
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingExceptionTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/ErrorResponseTest.java
index 9b502d3f67a..ad2e06da19c 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/metric/model/json/JsonRenderingExceptionTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/ErrorResponseTest.java
@@ -2,7 +2,7 @@
* Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
*/
-package ai.vespa.metricsproxy.metric.model.json;
+package ai.vespa.metricsproxy.http;
import org.junit.Test;
@@ -11,17 +11,18 @@ import static org.junit.Assert.assertEquals;
/**
* @author gjoranv
*/
-public class JsonRenderingExceptionTest {
+public class ErrorResponseTest {
@Test
public void error_message_is_wrapped_in_json_object() {
- var exception = new JsonRenderingException("bad");
- assertEquals("{\"error\":\"bad\"}", exception.getMessageAsJson());
+ var json = ErrorResponse.asErrorJson("bad");
+ assertEquals("{\"error\":\"bad\"}", json);
}
@Test
public void quotes_are_escaped() {
- var exception = new JsonRenderingException("Message \" with \" embedded quotes.");
- assertEquals("{\"error\":\"Message \\\" with \\\" embedded quotes.\"}", exception.getMessageAsJson());
+ var json = ErrorResponse.asErrorJson("Message \" with \" embedded quotes.");
+ assertEquals("{\"error\":\"Message \\\" with \\\" embedded quotes.\"}", json);
}
+
}
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/GenericMetricsHandlerTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/MetricsHandlerTest.java
index dc89e5bb9f2..66220464e3e 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/GenericMetricsHandlerTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/MetricsHandlerTest.java
@@ -26,6 +26,8 @@ import ai.vespa.metricsproxy.service.VespaServices;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.yahoo.container.jdisc.RequestHandlerTestDriver;
+import org.json.JSONArray;
+import org.json.JSONObject;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
@@ -36,9 +38,10 @@ import java.util.List;
import java.util.concurrent.Executors;
import static ai.vespa.metricsproxy.core.VespaMetrics.INSTANCE_DIMENSION_ID;
-import static ai.vespa.metricsproxy.http.GenericMetricsHandler.DEFAULT_PUBLIC_CONSUMER_ID;
+import static ai.vespa.metricsproxy.http.MetricsHandler.V1_PATH;
+import static ai.vespa.metricsproxy.http.MetricsHandler.VALUES_PATH;
+import static ai.vespa.metricsproxy.http.ValuesFetcher.DEFAULT_PUBLIC_CONSUMER_ID;
import static ai.vespa.metricsproxy.metric.ExternalMetrics.VESPA_NODE_SERVICE_ID;
-import static ai.vespa.metricsproxy.metric.model.ServiceId.toServiceId;
import static ai.vespa.metricsproxy.metric.model.StatusCode.DOWN;
import static ai.vespa.metricsproxy.metric.model.json.JacksonUtil.createObjectMapper;
import static ai.vespa.metricsproxy.service.DummyService.METRIC_1;
@@ -46,13 +49,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author gjoranv
*/
@SuppressWarnings("UnstableApiUsage")
-public class GenericMetricsHandlerTest {
+public class MetricsHandlerTest {
private static final List<VespaService> testServices = ImmutableList.of(
new DummyService(0, ""),
@@ -66,7 +70,9 @@ public class GenericMetricsHandlerTest {
private static final String CPU_METRIC = "cpu";
- private static final String URI = "http://localhost/metrics/v1/values";
+ private static final String URI_BASE = "http://localhost";
+ private static final String V1_URI = URI_BASE + V1_PATH;
+ private static final String VALUES_URI = URI_BASE + VALUES_PATH;
private static RequestHandlerTestDriver testDriver;
@@ -78,12 +84,12 @@ public class GenericMetricsHandlerTest {
new MetricsPacket.Builder(VESPA_NODE_SERVICE_ID)
.timestamp(Instant.now().getEpochSecond())
.putMetrics(ImmutableList.of(new Metric(CPU_METRIC, 12.345)))));
- GenericMetricsHandler handler = new GenericMetricsHandler(Executors.newSingleThreadExecutor(), metricsManager, vespaServices, getMetricsConsumers());
+ MetricsHandler handler = new MetricsHandler(Executors.newSingleThreadExecutor(), metricsManager, vespaServices, getMetricsConsumers());
testDriver = new RequestHandlerTestDriver(handler);
}
private GenericJsonModel getResponseAsJsonModel(String consumer) {
- String response = testDriver.sendRequest(URI + "?consumer=" + consumer).readAll();
+ String response = testDriver.sendRequest(VALUES_URI + "?consumer=" + consumer).readAll();
try {
return createObjectMapper().readValue(response, GenericJsonModel.class);
} catch (IOException e) {
@@ -92,10 +98,23 @@ public class GenericMetricsHandlerTest {
}
}
+ @Test
+ public void v1_response_contains_values_uri() throws Exception {
+ String response = testDriver.sendRequest(V1_URI).readAll();
+ JSONObject root = new JSONObject(response);
+ assertTrue(root.has("resources"));
+
+ JSONArray resources = root.getJSONArray("resources");
+ assertEquals(1, resources.length());
+
+ JSONObject valuesUrl = resources.getJSONObject(0);
+ assertEquals(VALUES_URI, valuesUrl.getString("url"));
+ }
+
@Ignore
@Test
- public void visually_inspect_response() throws Exception{
- String response = testDriver.sendRequest(URI+ "?consumer=default").readAll();
+ public void visually_inspect_values_response() throws Exception{
+ String response = testDriver.sendRequest(VALUES_URI).readAll();
ObjectMapper mapper = createObjectMapper();
var jsonModel = mapper.readValue(response, GenericJsonModel.class);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonModel));
@@ -103,15 +122,15 @@ public class GenericMetricsHandlerTest {
@Test
public void no_explicit_consumer_gives_the_default_consumer() {
- String responseDefaultConsumer = testDriver.sendRequest(URI + "?consumer=default").readAll();
- String responseNoConsumer = testDriver.sendRequest(URI).readAll();
+ String responseDefaultConsumer = testDriver.sendRequest(VALUES_URI + "?consumer=default").readAll();
+ String responseNoConsumer = testDriver.sendRequest(VALUES_URI).readAll();
assertEqualsExceptTimestamps(responseDefaultConsumer, responseNoConsumer);
}
@Test
public void unknown_consumer_gives_the_default_consumer() {
- String response = testDriver.sendRequest(URI).readAll();
- String responseUnknownConsumer = testDriver.sendRequest(URI + "?consumer=not_defined").readAll();
+ String response = testDriver.sendRequest(VALUES_URI).readAll();
+ String responseUnknownConsumer = testDriver.sendRequest(VALUES_URI + "?consumer=not_defined").readAll();
assertEqualsExceptTimestamps(response, responseUnknownConsumer);
}