summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-02-02 16:04:50 +0100
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-02-02 16:04:50 +0100
commit3ab3ce18ca6c6ef721cba5c11fde3d987816f56f (patch)
treec2a7ff592f3f665b87f4ee4c9182b2bdd555b3cb
parent10a9d8ec4d23b0ec8d1fa58d1ba148258f5f2bcb (diff)
Remove usage of org.json
-rw-r--r--container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java23
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java25
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java31
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java87
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/JsonUtil.java15
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java6
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java68
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java120
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java49
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java27
-rw-r--r--container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java13
-rw-r--r--container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java21
-rw-r--r--container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java63
-rw-r--r--metrics-proxy/pom.xml5
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java36
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java16
-rw-r--r--metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java55
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java25
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java18
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java17
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java19
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java79
-rw-r--r--metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java3
23 files changed, 389 insertions, 432 deletions
diff --git a/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java b/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java
index 92840cee48f..8c902f88e38 100644
--- a/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java
+++ b/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java
@@ -1,13 +1,14 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.handler.metrics;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
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;
@@ -26,6 +27,8 @@ import static java.util.logging.Level.WARNING;
*/
public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
protected HttpHandlerBase(Executor executor) {
super(executor);
}
@@ -49,15 +52,14 @@ public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler {
protected JsonResponse resourceListResponse(URI requestUri, List<String> resources) {
try {
return new JsonResponse(OK, resourceList(requestUri, resources));
- } catch (JSONException e) {
+ } catch (JsonProcessingException 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 {
+ private static String resourceList(URI requestUri, List<String> resources) throws JsonProcessingException {
int port = requestUri.getPort();
String host = requestUri.getHost();
StringBuilder base = new StringBuilder("http://");
@@ -66,13 +68,14 @@ public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler {
base.append(":").append(port);
}
String uriBase = base.toString();
- JSONArray linkList = new JSONArray();
+ ArrayNode linkList = jsonMapper.createArrayNode();
for (String api : resources) {
- JSONObject resource = new JSONObject();
+ ObjectNode resource = jsonMapper.createObjectNode();
resource.put("url", uriBase + api);
- linkList.put(resource);
+ linkList.add(resource);
}
- return new JSONObject().put("resources", linkList).toString(4);
+ return jsonMapper.writerWithDefaultPrettyPrinter()
+ .writeValueAsString(jsonMapper.createObjectNode().set("resources", linkList));
}
}
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java
index d105eaa9d98..f1ef7894511 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java
@@ -1,17 +1,16 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yahoo.vespa.defaults.Defaults;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.time.Instant;
-import java.util.Set;
import java.util.stream.Stream;
/**
@@ -19,19 +18,17 @@ import java.util.stream.Stream;
*/
public class CoredumpGatherer {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final Path COREDUMP_PATH = Path.of(Defaults.getDefaults().underVespaHome("var/crash/processing"));
- public static JSONObject gatherCoredumpMetrics(FileWrapper fileWrapper) {
+ public static JsonNode gatherCoredumpMetrics(FileWrapper fileWrapper) {
int coredumps = getNumberOfCoredumps(fileWrapper);
- JSONObject packet = new JSONObject();
-
- try {
- packet.put("status_code", coredumps == 0 ? 0 : 1);
- packet.put("status_msg", coredumps == 0 ? "OK" : String.format("Found %d coredump(s)", coredumps));
- packet.put("timestamp", Instant.now().getEpochSecond());
- packet.put("application", "system-coredumps-processing");
-
- } catch (JSONException e) {}
+ ObjectNode packet = jsonMapper.createObjectNode();
+ packet.put("status_code", coredumps == 0 ? 0 : 1);
+ packet.put("status_msg", coredumps == 0 ? "OK" : String.format("Found %d coredump(s)", coredumps));
+ packet.put("timestamp", Instant.now().getEpochSecond());
+ packet.put("application", "system-coredumps-processing");
return packet;
}
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java
index 730f7bc13cd..28f99096d84 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java
@@ -1,8 +1,9 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
-import org.json.JSONException;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.nio.file.Path;
@@ -13,9 +14,11 @@ import java.time.Instant;
*/
public class HostLifeGatherer {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final Path UPTIME_PATH = Path.of("/proc");
- public static JSONObject getHostLifePacket(FileWrapper fileWrapper) {
+ public static JsonNode getHostLifePacket(FileWrapper fileWrapper) {
long upTime;
int statusCode = 0;
String statusMessage = "OK";
@@ -29,19 +32,15 @@ public class HostLifeGatherer {
}
- JSONObject jsonObject = new JSONObject();
- try {
- jsonObject.put("status_code", statusCode);
- jsonObject.put("status_msg", statusMessage);
- jsonObject.put("timestamp", Instant.now().getEpochSecond());
- jsonObject.put("application", "host_life");
- JSONObject metrics = new JSONObject();
- metrics.put("uptime", upTime);
- metrics.put("alive", 1);
- jsonObject.put("metrics", metrics);
-
- } catch (JSONException e) {}
-
+ ObjectNode jsonObject = jsonMapper.createObjectNode();
+ jsonObject.put("status_code", statusCode);
+ jsonObject.put("status_msg", statusMessage);
+ jsonObject.put("timestamp", Instant.now().getEpochSecond());
+ jsonObject.put("application", "host_life");
+ ObjectNode metrics = jsonMapper.createObjectNode();
+ metrics.put("uptime", upTime);
+ metrics.put("alive", 1);
+ jsonObject.set("metrics", metrics);
return jsonObject;
}
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java
deleted file mode 100644
index d22dd9d6f4b..00000000000
--- a/container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.state;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * A JSONObject that wraps the checked JSONException in a RuntimeException with a legible error message.
- *
- * @author gjoranv
- */
-class JSONObjectWithLegibleException extends JSONObject {
-
- @Override
- public JSONObject put(String s, boolean b) {
- try {
- return super.put(s, b);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, b, e), e);
- }
- }
-
- @Override
- public JSONObject put(String s, double v) {
- try {
- Double guardedVal = (((Double) v).isNaN() || ((Double) v).isInfinite()) ?
- 0.0 : v;
- return super.put(s, guardedVal);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, v, e), e);
- }
- }
-
- @Override
- public JSONObject put(String s, int i) {
- try {
- return super.put(s, i);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, i, e), e);
- }
- }
-
- @Override
- public JSONObject put(String s, long l) {
- try {
- return super.put(s, l);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, l, e), e);
- }
- }
-
- @Override
- public JSONObject put(String s, Collection collection) {
- try {
- return super.put(s, collection);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, collection, e), e);
- }
- }
-
- @Override
- public JSONObject put(String s, Map map) {
- try {
- return super.put(s, map);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, map, e), e);
- }
- }
-
- @Override
- public JSONObject put(String s, Object o) {
- try {
- return super.put(s, o);
- } catch (JSONException e) {
- throw new RuntimeException(getErrorMessage(s, o, e), e);
- }
- }
-
- private String getErrorMessage(String key, Object value, JSONException e) {
- return "Trying to add invalid JSON object with key '" + key +
- "' and value '" + value + "' - " + e.getMessage();
- }
-
-}
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/JsonUtil.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/JsonUtil.java
new file mode 100644
index 00000000000..4c697fb5ada
--- /dev/null
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/JsonUtil.java
@@ -0,0 +1,15 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.jdisc.state;
+
+/**
+ * @author bjorncs
+ */
+class JsonUtil {
+
+ private JsonUtil() {}
+
+ static double sanitizeDouble(double value) {
+ return (((Double) value).isNaN() || ((Double) value).isInfinite()) ? 0.0 : value;
+ }
+
+}
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java
index 6a06a6362f5..add69403455 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java
@@ -1,7 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList;
import java.util.List;
@@ -13,9 +13,9 @@ import java.util.List;
*/
public class MetricGatherer {
- static List<JSONObject> getAdditionalMetrics() {
+ static List<JsonNode> getAdditionalMetrics() {
FileWrapper fileWrapper = new FileWrapper();
- List<JSONObject> packetList = new ArrayList<>();
+ List<JsonNode> packetList = new ArrayList<>();
packetList.add(CoredumpGatherer.gatherCoredumpMetrics(fileWrapper));
if (System.getProperty("os.name").contains("nux"))
packetList.add(HostLifeGatherer.getHostLifePacket(fileWrapper));
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java
index 3d3f0e4b677..824323af3d6 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java
@@ -1,6 +1,11 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.inject.Inject;
import com.yahoo.collections.Tuple2;
import com.yahoo.component.provider.ComponentRegistry;
@@ -13,9 +18,6 @@ import com.yahoo.jdisc.handler.ResponseDispatch;
import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.metrics.MetricsPresentationConfig;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -26,6 +28,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import static com.yahoo.container.jdisc.state.JsonUtil.sanitizeDouble;
import static com.yahoo.container.jdisc.state.StateHandler.getSnapshotPreprocessor;
/**
@@ -44,6 +47,8 @@ import static com.yahoo.container.jdisc.state.StateHandler.getSnapshotPreprocess
*/
public class MetricsPacketsHandler extends AbstractRequestHandler {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
static final String APPLICATION_KEY = "application";
static final String TIMESTAMP_KEY = "timestamp";
static final String STATUS_CODE_KEY = "status_code";
@@ -97,19 +102,19 @@ public class MetricsPacketsHandler extends AbstractRequestHandler {
}
String output = jsonToString(getStatusPacket()) + getAllMetricsPackets() + "\n";
return output.getBytes(StandardCharsets.UTF_8);
- } catch (JSONException e) {
+ } catch (JsonProcessingException e) {
throw new RuntimeException("Bad JSON construction.", e);
}
}
- private byte[] getMetricsArray() throws JSONException {
- JSONObject root = new JSONObject();
- JSONArray jsonArray = new JSONArray();
- jsonArray.put(getStatusPacket());
+ private byte[] getMetricsArray() throws JsonProcessingException {
+ ObjectNode root = jsonMapper.createObjectNode();
+ ArrayNode jsonArray = jsonMapper.createArrayNode();
+ jsonArray.add(getStatusPacket());
getPacketsForSnapshot(getSnapshot(), applicationName, timer.currentTimeMillis())
- .forEach(jsonArray::put);
- MetricGatherer.getAdditionalMetrics().forEach(jsonArray::put);
- root.put("metrics", jsonArray);
+ .forEach(jsonArray::add);
+ MetricGatherer.getAdditionalMetrics().forEach(jsonArray::add);
+ root.set("metrics", jsonArray);
return jsonToString(root)
.getBytes(StandardCharsets.UTF_8);
}
@@ -117,8 +122,8 @@ public class MetricsPacketsHandler extends AbstractRequestHandler {
/**
* Exactly one status packet is added to the response.
*/
- private JSONObject getStatusPacket() throws JSONException {
- JSONObject packet = new JSONObjectWithLegibleException();
+ private JsonNode getStatusPacket() {
+ ObjectNode packet = jsonMapper.createObjectNode();
packet.put(APPLICATION_KEY, applicationName);
StateMonitor.Status status = monitor.status();
@@ -127,14 +132,15 @@ public class MetricsPacketsHandler extends AbstractRequestHandler {
return packet;
}
- private String jsonToString(JSONObject jsonObject) throws JSONException {
- return jsonObject.toString(4);
+ private static String jsonToString(JsonNode jsonObject) throws JsonProcessingException {
+ return jsonMapper.writerWithDefaultPrettyPrinter()
+ .writeValueAsString(jsonObject);
}
- private String getAllMetricsPackets() throws JSONException {
+ private String getAllMetricsPackets() throws JsonProcessingException {
StringBuilder ret = new StringBuilder();
- List<JSONObject> metricsPackets = getPacketsForSnapshot(getSnapshot(), applicationName, timer.currentTimeMillis());
- for (JSONObject packet : metricsPackets) {
+ List<JsonNode> metricsPackets = getPacketsForSnapshot(getSnapshot(), applicationName, timer.currentTimeMillis());
+ for (JsonNode packet : metricsPackets) {
ret.append(PACKET_SEPARATOR); // For legibility and parsing in unit tests
ret.append(jsonToString(packet));
}
@@ -150,16 +156,16 @@ public class MetricsPacketsHandler extends AbstractRequestHandler {
}
}
- private List<JSONObject> getPacketsForSnapshot(MetricSnapshot metricSnapshot, String application, long timestamp) throws JSONException {
+ private List<JsonNode> getPacketsForSnapshot(MetricSnapshot metricSnapshot, String application, long timestamp) {
if (metricSnapshot == null) return Collections.emptyList();
- List<JSONObject> packets = new ArrayList<>();
+ List<JsonNode> packets = new ArrayList<>();
for (Map.Entry<MetricDimensions, MetricSet> snapshotEntry : metricSnapshot) {
MetricDimensions metricDimensions = snapshotEntry.getKey();
MetricSet metricSet = snapshotEntry.getValue();
- JSONObjectWithLegibleException packet = new JSONObjectWithLegibleException();
+ ObjectNode packet = jsonMapper.createObjectNode();
addMetaData(timestamp, application, packet);
addDimensions(metricDimensions, packet);
addMetrics(metricSet, packet);
@@ -168,27 +174,27 @@ public class MetricsPacketsHandler extends AbstractRequestHandler {
return packets;
}
- private void addMetaData(long timestamp, String application, JSONObjectWithLegibleException packet) {
+ private void addMetaData(long timestamp, String application, ObjectNode packet) {
packet.put(APPLICATION_KEY, application);
packet.put(TIMESTAMP_KEY, TimeUnit.MILLISECONDS.toSeconds(timestamp));
}
- private void addDimensions(MetricDimensions metricDimensions, JSONObjectWithLegibleException packet) throws JSONException {
+ private void addDimensions(MetricDimensions metricDimensions, ObjectNode packet) {
if (metricDimensions == null) return;
Iterator<Map.Entry<String, String>> dimensionsIterator = metricDimensions.iterator();
if (dimensionsIterator.hasNext()) {
- JSONObject jsonDim = new JSONObjectWithLegibleException();
- packet.put(DIMENSIONS_KEY, jsonDim);
+ ObjectNode jsonDim = jsonMapper.createObjectNode();
+ packet.set(DIMENSIONS_KEY, jsonDim);
for (Map.Entry<String, String> dimensionEntry : metricDimensions) {
jsonDim.put(dimensionEntry.getKey(), dimensionEntry.getValue());
}
}
}
- private void addMetrics(MetricSet metricSet, JSONObjectWithLegibleException packet) throws JSONException {
- JSONObjectWithLegibleException metrics = new JSONObjectWithLegibleException();
- packet.put(METRICS_KEY, metrics);
+ private void addMetrics(MetricSet metricSet, ObjectNode packet) {
+ ObjectNode metrics = jsonMapper.createObjectNode();
+ packet.set(METRICS_KEY, metrics);
for (Map.Entry<String, MetricValue> metric : metricSet) {
String name = metric.getKey();
MetricValue value = metric.getValue();
@@ -196,9 +202,9 @@ public class MetricsPacketsHandler extends AbstractRequestHandler {
metrics.put(name + ".count", ((CountMetric) value).getCount());
} else if (value instanceof GaugeMetric) {
GaugeMetric gauge = (GaugeMetric) value;
- metrics.put(name + ".average", gauge.getAverage())
- .put(name + ".last", gauge.getLast())
- .put(name + ".max", gauge.getMax());
+ metrics.put(name + ".average", sanitizeDouble(gauge.getAverage()))
+ .put(name + ".last", sanitizeDouble(gauge.getLast()))
+ .put(name + ".max", sanitizeDouble(gauge.getMax()));
if (gauge.getPercentiles().isPresent()) {
for (Tuple2<String, Double> prefixAndValue : gauge.getPercentiles().get()) {
metrics.put(name + "." + prefixAndValue.first + "percentile", prefixAndValue.second.doubleValue());
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java
index b14dc50edcb..5ac2871d9dd 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java
@@ -1,6 +1,11 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.inject.Inject;
import com.yahoo.collections.Tuple2;
import com.yahoo.component.Vtag;
@@ -16,21 +21,18 @@ import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.metrics.MetricsPresentationConfig;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import java.net.URI;
import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import java.io.PrintStream;
-import java.io.ByteArrayOutputStream;
+
+import static com.yahoo.container.jdisc.state.JsonUtil.sanitizeDouble;
/**
* A handler which returns state (health) information from this container instance: Status, metrics and vespa version.
@@ -39,6 +41,8 @@ import java.io.ByteArrayOutputStream;
*/
public class StateHandler extends AbstractRequestHandler {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
public static final String STATE_API_ROOT = "/state/v1";
private static final String METRICS_PATH = "metrics";
private static final String HISTOGRAMS_PATH = "metrics/histograms";
@@ -124,17 +128,16 @@ public class StateHandler extends AbstractRequestHandler {
}
base.append(STATE_API_ROOT);
String uriBase = base.toString();
- JSONArray linkList = new JSONArray();
+ ArrayNode linkList = jsonMapper.createArrayNode();
for (String api : new String[] {METRICS_PATH, CONFIG_GENERATION_PATH, HEALTH_PATH, VERSION_PATH}) {
- JSONObject resource = new JSONObject();
+ ObjectNode resource = jsonMapper.createObjectNode();
resource.put("url", uriBase + "/" + api);
- linkList.put(resource);
+ linkList.add(resource);
}
- return new JSONObjectWithLegibleException()
- .put("resources", linkList)
- .toString(4).getBytes(StandardCharsets.UTF_8);
- } catch (JSONException e) {
- throw new RuntimeException("Bad JSON construction.", e);
+ JsonNode resources = jsonMapper.createObjectNode().set("resources", linkList);
+ return toPrettyString(resources);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("Bad JSON construction", e);
}
}
@@ -154,31 +157,31 @@ public class StateHandler extends AbstractRequestHandler {
private static byte[] buildConfigOutput(ApplicationMetadataConfig config) {
try {
- return new JSONObjectWithLegibleException()
- .put(CONFIG_GENERATION_PATH, new JSONObjectWithLegibleException()
- .put("generation", config.generation())
- .put("container", new JSONObjectWithLegibleException()
- .put("generation", config.generation())))
- .toString(4).getBytes(StandardCharsets.UTF_8);
- } catch (JSONException e) {
+ return toPrettyString(
+ jsonMapper.createObjectNode()
+ .set(CONFIG_GENERATION_PATH, jsonMapper.createObjectNode()
+ .put("generation", config.generation())
+ .set("container", jsonMapper.createObjectNode()
+ .put("generation", config.generation()))));
+ } catch (JsonProcessingException e) {
throw new RuntimeException("Bad JSON construction.", e);
}
}
private static byte[] buildVersionOutput() {
try {
- return new JSONObjectWithLegibleException()
- .put("version", Vtag.currentVersion)
- .toString(4).getBytes(StandardCharsets.UTF_8);
- } catch (JSONException e) {
+ return toPrettyString(
+ jsonMapper.createObjectNode()
+ .put("version", Vtag.currentVersion.toString()));
+ } catch (JsonProcessingException e) {
throw new RuntimeException("Bad JSON construction.", e);
}
}
private byte[] buildMetricOutput(String consumer) {
try {
- return buildJsonForConsumer(consumer).toString(4).getBytes(StandardCharsets.UTF_8);
- } catch (JSONException e) {
+ return toPrettyString(buildJsonForConsumer(consumer));
+ } catch (JsonProcessingException e) {
throw new RuntimeException("Bad JSON construction.", e);
}
}
@@ -191,11 +194,11 @@ public class StateHandler extends AbstractRequestHandler {
return baos.toByteArray();
}
- private JSONObjectWithLegibleException buildJsonForConsumer(String consumer) throws JSONException {
- JSONObjectWithLegibleException ret = new JSONObjectWithLegibleException();
+ private ObjectNode buildJsonForConsumer(String consumer) {
+ ObjectNode ret = jsonMapper.createObjectNode();
ret.put("time", timer.currentTimeMillis());
- ret.put("status", new JSONObjectWithLegibleException().put("code", getStatus().name()));
- ret.put(METRICS_PATH, buildJsonForSnapshot(consumer, getSnapshot()));
+ ret.set("status", jsonMapper.createObjectNode().put("code", getStatus().name()));
+ ret.set(METRICS_PATH, buildJsonForSnapshot(consumer, getSnapshot()));
return ret;
}
@@ -212,57 +215,62 @@ public class StateHandler extends AbstractRequestHandler {
return monitor.status();
}
- private JSONObjectWithLegibleException buildJsonForSnapshot(String consumer, MetricSnapshot metricSnapshot) throws JSONException {
+ private ObjectNode buildJsonForSnapshot(String consumer, MetricSnapshot metricSnapshot) {
if (metricSnapshot == null) {
- return new JSONObjectWithLegibleException();
+ return jsonMapper.createObjectNode();
}
- JSONObjectWithLegibleException jsonMetric = new JSONObjectWithLegibleException();
- jsonMetric.put("snapshot", new JSONObjectWithLegibleException()
- .put("from", metricSnapshot.getFromTime(TimeUnit.MILLISECONDS) / 1000.0)
- .put("to", metricSnapshot.getToTime(TimeUnit.MILLISECONDS) / 1000.0));
+ ObjectNode jsonMetric = jsonMapper.createObjectNode();
+ jsonMetric.set("snapshot", jsonMapper.createObjectNode()
+ .put("from", sanitizeDouble(metricSnapshot.getFromTime(TimeUnit.MILLISECONDS) / 1000.0))
+ .put("to", sanitizeDouble(metricSnapshot.getToTime(TimeUnit.MILLISECONDS) / 1000.0)));
boolean includeDimensions = !consumer.equals(HEALTH_PATH);
long periodInMillis = metricSnapshot.getToTime(TimeUnit.MILLISECONDS) -
metricSnapshot.getFromTime(TimeUnit.MILLISECONDS);
for (Tuple tuple : collapseMetrics(metricSnapshot, consumer)) {
- JSONObjectWithLegibleException jsonTuple = new JSONObjectWithLegibleException();
+ ObjectNode jsonTuple = jsonMapper.createObjectNode();
jsonTuple.put("name", tuple.key);
if (tuple.val instanceof CountMetric) {
CountMetric count = (CountMetric)tuple.val;
- jsonTuple.put("values", new JSONObjectWithLegibleException()
+ jsonTuple.set("values", jsonMapper.createObjectNode()
.put("count", count.getCount())
- .put("rate", (count.getCount() * 1000.0) / periodInMillis));
+ .put("rate", sanitizeDouble(count.getCount() * 1000.0) / periodInMillis));
} else if (tuple.val instanceof GaugeMetric) {
GaugeMetric gauge = (GaugeMetric) tuple.val;
- JSONObjectWithLegibleException valueFields = new JSONObjectWithLegibleException();
- valueFields.put("average", gauge.getAverage())
- .put("sum", gauge.getSum())
+ ObjectNode valueFields = jsonMapper.createObjectNode();
+ valueFields.put("average", sanitizeDouble(gauge.getAverage()))
+ .put("sum", sanitizeDouble(gauge.getSum()))
.put("count", gauge.getCount())
- .put("last", gauge.getLast())
- .put("max", gauge.getMax())
- .put("min", gauge.getMin())
- .put("rate", (gauge.getCount() * 1000.0) / periodInMillis);
+ .put("last", sanitizeDouble(gauge.getLast()))
+ .put("max", sanitizeDouble(gauge.getMax()))
+ .put("min", sanitizeDouble(gauge.getMin()))
+ .put("rate", sanitizeDouble((gauge.getCount() * 1000.0) / periodInMillis));
if (gauge.getPercentiles().isPresent()) {
for (Tuple2<String, Double> prefixAndValue : gauge.getPercentiles().get()) {
- valueFields.put(prefixAndValue.first + "percentile", prefixAndValue.second.doubleValue());
+ valueFields.put(prefixAndValue.first + "percentile", sanitizeDouble(prefixAndValue.second));
}
}
- jsonTuple.put("values", valueFields);
+ jsonTuple.set("values", valueFields);
} else {
throw new UnsupportedOperationException(tuple.val.getClass().getName());
}
if (tuple.dim != null) {
Iterator<Map.Entry<String, String>> it = tuple.dim.iterator();
if (it.hasNext() && includeDimensions) {
- JSONObjectWithLegibleException jsonDim = new JSONObjectWithLegibleException();
+ ObjectNode jsonDim = jsonMapper.createObjectNode();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
jsonDim.put(entry.getKey(), entry.getValue());
}
- jsonTuple.put("dimensions", jsonDim);
+ jsonTuple.set("dimensions", jsonDim);
}
}
- jsonMetric.append("values", jsonTuple);
+ ArrayNode values = (ArrayNode) jsonMetric.get("values");
+ if (values == null) {
+ values = jsonMapper.createArrayNode();
+ jsonMetric.set("values", values);
+ }
+ values.add(jsonTuple);
}
return jsonMetric;
}
@@ -316,6 +324,12 @@ public class StateHandler extends AbstractRequestHandler {
return metrics;
}
+ private static byte[] toPrettyString(JsonNode resources) throws JsonProcessingException {
+ return jsonMapper.writerWithDefaultPrettyPrinter()
+ .writeValueAsString(resources)
+ .getBytes();
+ }
+
static class Tuple {
final MetricDimensions dim;
diff --git a/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java b/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java
index 9020ed91026..ca4bec30322 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java
@@ -1,17 +1,18 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.handler.metrics;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.yahoo.container.jdisc.RequestHandlerTestDriver;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Executors;
@@ -34,6 +35,8 @@ import static org.junit.Assert.fail;
*/
public class MetricsV2HandlerTest {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final String URI_BASE = "http://localhost";
private static final String V2_URI = URI_BASE + V2_PATH;
@@ -79,29 +82,29 @@ public class MetricsV2HandlerTest {
@Test
public void v2_response_contains_values_uri() throws Exception {
String response = testDriver.sendRequest(V2_URI).readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("resources"));
- JSONArray resources = root.getJSONArray("resources");
- assertEquals(1, resources.length());
+ ArrayNode resources = (ArrayNode) root.get("resources");
+ assertEquals(1, resources.size());
- JSONObject valuesUri = resources.getJSONObject(0);
- assertEquals(VALUES_URI, valuesUri.getString("url"));
+ JsonNode valuesUri = resources.get(0);
+ assertEquals(VALUES_URI, valuesUri.get("url").textValue());
}
@Ignore
@Test
- public void visually_inspect_values_response() throws Exception {
- JSONObject responseJson = getResponseAsJson(null);
- System.out.println(responseJson.toString(4));
+ public void visually_inspect_values_response() {
+ JsonNode responseJson = getResponseAsJson(null);
+ System.out.println(responseJson);
}
@Test
public void invalid_path_yields_error_response() throws Exception {
String response = testDriver.sendRequest(V2_URI + "/invalid").readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("error"));
- assertTrue(root.getString("error" ).startsWith("No content"));
+ assertTrue(root.get("error" ).textValue().startsWith("No content"));
}
@Test
@@ -111,23 +114,23 @@ public class MetricsV2HandlerTest {
}
@Test
- public void consumer_is_propagated_to_metrics_proxy_api() throws JSONException {
- JSONObject responseJson = getResponseAsJson(CUSTOM_CONSUMER);
+ public void consumer_is_propagated_to_metrics_proxy_api() {
+ JsonNode responseJson = getResponseAsJson(CUSTOM_CONSUMER);
- JSONObject firstNodeMetricsValues =
- responseJson.getJSONArray("nodes").getJSONObject(0)
- .getJSONObject("node")
- .getJSONArray("metrics").getJSONObject(0)
- .getJSONObject("values");
+ JsonNode firstNodeMetricsValues =
+ responseJson.get("nodes").get(0)
+ .get("node")
+ .get("metrics").get(0)
+ .get("values");
assertTrue(firstNodeMetricsValues.has(REPLACED_CPU_METRIC));
}
- private JSONObject getResponseAsJson(String consumer) {
+ private JsonNode getResponseAsJson(String consumer) {
String response = testDriver.sendRequest(VALUES_URI + consumerQuery(consumer)).readAll();
try {
- return new JSONObject(response);
- } catch (JSONException e) {
+ return jsonMapper.readTree(response);
+ } catch (IOException e) {
fail("Failed to create json object: " + e.getMessage());
throw new RuntimeException(e);
}
diff --git a/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java b/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java
index a0e8c131c2b..9ffce6d1c28 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java
@@ -1,15 +1,11 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.handler.metrics;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.yahoo.container.jdisc.RequestHandlerTestDriver;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.stream.Collectors;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -26,13 +22,14 @@ import static com.yahoo.container.handler.metrics.MetricsV2Handler.consumerQuery
import static com.yahoo.container.handler.metrics.MetricsV2HandlerTest.getFileContents;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
/**
* @author gjoranv
*/
public class PrometheusV1HandlerTest {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final String URI_BASE = "http://localhost";
private static final String V1_URI = URI_BASE + PrometheusV1Handler.V1_PATH;
@@ -79,14 +76,14 @@ public class PrometheusV1HandlerTest {
@Test
public void v1_response_contains_values_uri() throws Exception {
String response = testDriver.sendRequest(V1_URI).readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("resources"));
- JSONArray resources = root.getJSONArray("resources");
- assertEquals(1, resources.length());
+ ArrayNode resources = (ArrayNode) root.get("resources");
+ assertEquals(1, resources.size());
- JSONObject valuesUri = resources.getJSONObject(0);
- assertEquals(VALUES_URI, valuesUri.getString("url"));
+ JsonNode valuesUri = resources.get(0);
+ assertEquals(VALUES_URI, valuesUri.get("url").asText());
}
@Ignore
@@ -99,9 +96,9 @@ public class PrometheusV1HandlerTest {
@Test
public void invalid_path_yields_error_response() throws Exception {
String response = testDriver.sendRequest(V1_URI + "/invalid").readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("error"));
- assertTrue(root.getString("error" ).startsWith("No content"));
+ assertTrue(root.get("error" ).textValue().startsWith("No content"));
}
@Test
diff --git a/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java b/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java
index c1f7d790fa5..8a3d0e837c5 100644
--- a/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java
+++ b/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java
@@ -1,8 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
-import org.json.JSONException;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Test;
import java.nio.file.Path;
@@ -17,12 +16,12 @@ import static org.junit.Assert.assertEquals;
public class CoredumpGathererTest {
@Test
- public void finds_one_coredump() throws JSONException {
- JSONObject packet = CoredumpGatherer.gatherCoredumpMetrics(new MockFileWrapper());
+ public void finds_one_coredump() {
+ JsonNode packet = CoredumpGatherer.gatherCoredumpMetrics(new MockFileWrapper());
- assertEquals("system-coredumps-processing", packet.getString("application"));
- assertEquals(1, packet.getInt("status_code"));
- assertEquals("Found 1 coredump(s)", packet.getString("status_msg"));
+ assertEquals("system-coredumps-processing", packet.get("application").textValue());
+ assertEquals(1, packet.get("status_code").intValue());
+ assertEquals("Found 1 coredump(s)", packet.get("status_msg").textValue());
}
diff --git a/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java b/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java
index d025b9662d2..12852c9d54c 100644
--- a/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java
+++ b/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java
@@ -1,8 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.jdisc.state;
-import org.json.JSONException;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Test;
import java.nio.file.Path;
@@ -16,15 +15,15 @@ import static org.junit.Assert.assertEquals;
public class HostLifeGathererTest {
@Test
- public void host_is_alive() throws JSONException {
- JSONObject packet = HostLifeGatherer.getHostLifePacket(new MockFileWrapper());
- JSONObject metrics = packet.getJSONObject("metrics");
- assertEquals("host_life", packet.getString("application"));
- assertEquals(0, packet.getInt("status_code"));
- assertEquals("OK", packet.getString("status_msg"));
-
- assertEquals(123l, metrics.getLong("uptime"));
- assertEquals(1, metrics.getInt("alive"));
+ public void host_is_alive() {
+ JsonNode packet = HostLifeGatherer.getHostLifePacket(new MockFileWrapper());
+ JsonNode metrics = packet.get("metrics");
+ assertEquals("host_life", packet.get("application").textValue());
+ assertEquals(0, packet.get("status_code").intValue());
+ assertEquals("OK", packet.get("status_msg").textValue());
+
+ assertEquals(123L, metrics.get("uptime").longValue());
+ assertEquals(1, metrics.get("alive").intValue());
}
diff --git a/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java b/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java
index 1258ecdc46f..385eb627427 100644
--- a/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java
+++ b/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java
@@ -98,37 +98,38 @@ public class StateHandlerTest extends StateHandlerTestBase {
snapshotProvider.setSnapshot(snapshot);
advanceToNextSnapshot();
assertEquals("{\n" +
- " \"metrics\": {\n" +
- " \"snapshot\": {\n" +
- " \"from\": 0,\n" +
- " \"to\": 300\n" +
- " },\n" +
- " \"values\": [\n" +
- " {\n" +
- " \"name\": \"foo\",\n" +
- " \"values\": {\n" +
- " \"count\": 1,\n" +
- " \"rate\": 0.0033333333333333335\n" +
- " }\n" +
- " },\n" +
- " {\n" +
- " \"dimensions\": {\"component\": \"test\"},\n" +
- " \"name\": \"bar\",\n" +
- " \"values\": {\n" +
- " \"average\": 3.5,\n" +
- " \"count\": 4,\n" +
- " \"last\": 5,\n" +
- " \"max\": 5,\n" +
- " \"min\": 2,\n" +
- " \"rate\": 0.013333333333333334,\n" +
- " \"sum\": 14\n" +
- " }\n" +
- " }\n" +
- " ]\n" +
- " },\n" +
- " \"status\": {\"code\": \"up\"},\n" +
- " \"time\": 300000\n" +
- "}",
+ " \"time\" : 300000,\n" +
+ " \"status\" : {\n" +
+ " \"code\" : \"up\"\n" +
+ " },\n" +
+ " \"metrics\" : {\n" +
+ " \"snapshot\" : {\n" +
+ " \"from\" : 0.0,\n" +
+ " \"to\" : 300.0\n" +
+ " },\n" +
+ " \"values\" : [ {\n" +
+ " \"name\" : \"foo\",\n" +
+ " \"values\" : {\n" +
+ " \"count\" : 1,\n" +
+ " \"rate\" : 0.0033333333333333335\n" +
+ " }\n" +
+ " }, {\n" +
+ " \"name\" : \"bar\",\n" +
+ " \"values\" : {\n" +
+ " \"average\" : 3.5,\n" +
+ " \"sum\" : 14.0,\n" +
+ " \"count\" : 4,\n" +
+ " \"last\" : 5.0,\n" +
+ " \"max\" : 5.0,\n" +
+ " \"min\" : 2.0,\n" +
+ " \"rate\" : 0.013333333333333334\n" +
+ " },\n" +
+ " \"dimensions\" : {\n" +
+ " \"component\" : \"test\"\n" +
+ " }\n" +
+ " } ]\n" +
+ " }\n" +
+ "}",
requestAsString(V1_URI + "all"));
}
diff --git a/metrics-proxy/pom.xml b/metrics-proxy/pom.xml
index 8bf5a30e584..90d9f093da1 100644
--- a/metrics-proxy/pom.xml
+++ b/metrics-proxy/pom.xml
@@ -101,11 +101,6 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>org.json</groupId>
- <artifactId>json</artifactId>
- <scope>provided</scope>
- </dependency>
<!-- compile scope -->
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java
index 3cd9f526387..0e0511967a3 100644
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java
@@ -9,13 +9,11 @@ import ai.vespa.metricsproxy.metric.model.MetricsPacket;
import ai.vespa.metricsproxy.metric.model.ServiceId;
import ai.vespa.metricsproxy.service.SystemPollerProvider;
import ai.vespa.metricsproxy.service.VespaServices;
+import com.fasterxml.jackson.databind.JsonNode;
import com.google.inject.Inject;
import com.yahoo.container.jdisc.state.CoredumpGatherer;
import com.yahoo.container.jdisc.state.FileWrapper;
import com.yahoo.container.jdisc.state.HostLifeGatherer;
-import com.yahoo.yolean.Exceptions;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
@@ -54,10 +52,10 @@ public class NodeMetricGatherer {
List<MetricsPacket.Builder> metricPacketBuilders = new ArrayList<>();
metricPacketBuilders.addAll(gatherServiceHealthMetrics(vespaServices));
- JSONObject coredumpPacket = CoredumpGatherer.gatherCoredumpMetrics(fileWrapper);
+ JsonNode coredumpPacket = CoredumpGatherer.gatherCoredumpMetrics(fileWrapper);
addObjectToBuilders(metricPacketBuilders, coredumpPacket);
if (SystemPollerProvider.runningOnLinux()) {
- JSONObject packet = HostLifeGatherer.getHostLifePacket(fileWrapper);
+ JsonNode packet = HostLifeGatherer.getHostLifePacket(fileWrapper);
addObjectToBuilders(metricPacketBuilders, packet);
}
@@ -69,24 +67,20 @@ public class NodeMetricGatherer {
).collect(Collectors.toList());
}
- protected static void addObjectToBuilders(List<MetricsPacket.Builder> builders, JSONObject object) {
- try {
- MetricsPacket.Builder builder = new MetricsPacket.Builder(ServiceId.toServiceId(object.getString("application")));
- builder.timestamp(object.getLong("timestamp"));
- if (object.has("status_code")) builder.statusCode(object.getInt("status_code"));
- if (object.has("status_msg")) builder.statusMessage(object.getString("status_msg"));
- if (object.has("metrics")) {
- JSONObject metrics = object.getJSONObject("metrics");
- Iterator<?> keys = metrics.keys();
- while(keys.hasNext()) {
- String key = (String) keys.next();
- builder.putMetric(MetricId.toMetricId(key), metrics.getLong(key));
- }
+ protected static void addObjectToBuilders(List<MetricsPacket.Builder> builders, JsonNode object) {
+ MetricsPacket.Builder builder = new MetricsPacket.Builder(ServiceId.toServiceId(object.get("application").textValue()));
+ builder.timestamp(object.get("timestamp").longValue());
+ if (object.has("status_code")) builder.statusCode(object.get("status_code").intValue());
+ if (object.has("status_msg")) builder.statusMessage(object.get("status_msg").textValue());
+ if (object.has("metrics")) {
+ JsonNode metrics = object.get("metrics");
+ Iterator<?> keys = metrics.fieldNames();
+ while(keys.hasNext()) {
+ String key = (String) keys.next();
+ builder.putMetric(MetricId.toMetricId(key), metrics.get(key).asLong());
}
- builders.add(builder);
- } catch (JSONException e) {
- Exceptions.toMessageString(e);
}
+ builders.add(builder);
}
}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java
index 1cab1a859a9..827f513a418 100644
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java
@@ -2,9 +2,10 @@
package ai.vespa.metricsproxy.service;
import ai.vespa.metricsproxy.metric.HealthMetric;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
import java.util.logging.Level;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.io.IOException;
import java.util.logging.Logger;
@@ -15,6 +16,7 @@ import java.util.logging.Logger;
* @author Jo Kristian Bergum
*/
public class RemoteHealthMetricFetcher extends HttpMetricFetcher {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
private final static Logger log = Logger.getLogger(RemoteHealthMetricFetcher.class.getPackage().getName());
private final static String HEALTH_PATH = STATE_PATH + "health";
@@ -54,16 +56,16 @@ public class RemoteHealthMetricFetcher extends HttpMetricFetcher {
return HealthMetric.getUnknown("Empty response from status page");
}
try {
- JSONObject o = new JSONObject(data);
- JSONObject status = o.getJSONObject("status");
- String code = status.getString("code");
+ JsonNode o = jsonMapper.readTree(data);
+ JsonNode status = o.get("status");
+ String code = status.get("code").asText();
String message = "";
if (status.has("message")) {
- message = status.getString("message");
+ message = status.get("message").textValue();
}
return HealthMetric.get(code, message);
- } catch (JSONException e) {
+ } catch (IOException e) {
log.log(Level.FINE, "Failed to parse json response from metrics page:" + e + ":" + data);
return HealthMetric.getUnknown("Not able to parse json from status page");
}
diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java
index 442ebc0d38d..464f215edc4 100644
--- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java
+++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java
@@ -4,9 +4,9 @@ package ai.vespa.metricsproxy.service;
import ai.vespa.metricsproxy.metric.Metric;
import ai.vespa.metricsproxy.metric.Metrics;
import ai.vespa.metricsproxy.metric.model.DimensionId;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.IOException;
import java.util.Collections;
@@ -23,6 +23,8 @@ import static ai.vespa.metricsproxy.metric.model.DimensionId.toDimensionId;
*/
public class RemoteMetricsFetcher extends HttpMetricFetcher {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
final static String METRICS_PATH = STATE_PATH + "metrics";
RemoteMetricsFetcher(VespaService service, int port) {
@@ -57,21 +59,21 @@ public class RemoteMetricsFetcher extends HttpMetricFetcher {
return remoteMetrics;
}
- private Metrics parse(String data) throws JSONException {
- JSONObject o = new JSONObject(data);
+ private Metrics parse(String data) throws IOException {
+ JsonNode o = jsonMapper.readTree(data);
if (!(o.has("metrics"))) {
return new Metrics(); //empty
}
- JSONObject metrics = o.getJSONObject("metrics");
- JSONArray values;
+ JsonNode metrics = o.get("metrics");
+ ArrayNode values;
long timestamp;
try {
- JSONObject snapshot = metrics.getJSONObject("snapshot");
- timestamp = (long) snapshot.getDouble("to");
- values = metrics.getJSONArray("values");
- } catch (JSONException e) {
+ JsonNode snapshot = metrics.get("snapshot");
+ timestamp = snapshot.get("to").asLong();
+ values = (ArrayNode) metrics.get("values");
+ } catch (Exception e) {
// snapshot might not have been produced. Do not throw exception into log
return new Metrics();
}
@@ -81,29 +83,29 @@ public class RemoteMetricsFetcher extends HttpMetricFetcher {
Map<DimensionId, String> noDims = Collections.emptyMap();
Map<String, Map<DimensionId, String>> uniqueDimensions = new HashMap<>();
- for (int i = 0; i < values.length(); i++) {
- JSONObject metric = values.getJSONObject(i);
- String name = metric.getString("name");
+ for (int i = 0; i < values.size(); i++) {
+ JsonNode metric = values.get(i);
+ String name = metric.get("name").textValue();
String description = "";
if (metric.has("description")) {
- description = metric.getString("description");
+ description = metric.get("description").textValue();
}
Map<DimensionId, String> dim = noDims;
if (metric.has("dimensions")) {
- JSONObject dimensions = metric.getJSONObject("dimensions");
+ JsonNode dimensions = metric.get("dimensions");
StringBuilder sb = new StringBuilder();
- for (Iterator<?> it = dimensions.keys(); it.hasNext(); ) {
+ for (Iterator<?> it = dimensions.fieldNames(); it.hasNext(); ) {
String k = (String) it.next();
- String v = dimensions.getString(k);
+ String v = dimensions.get(k).asText();
sb.append(toDimensionId(k)).append(v);
}
if ( ! uniqueDimensions.containsKey(sb.toString())) {
dim = new HashMap<>();
- for (Iterator<?> it = dimensions.keys(); it.hasNext(); ) {
+ for (Iterator<?> it = dimensions.fieldNames(); it.hasNext(); ) {
String k = (String) it.next();
- String v = dimensions.getString(k);
+ String v = dimensions.get(k).textValue();
dim.put(toDimensionId(k), v);
}
uniqueDimensions.put(sb.toString(), Collections.unmodifiableMap(dim));
@@ -111,10 +113,17 @@ public class RemoteMetricsFetcher extends HttpMetricFetcher {
dim = uniqueDimensions.get(sb.toString());
}
- JSONObject aggregates = metric.getJSONObject("values");
- for (Iterator<?> it = aggregates.keys(); it.hasNext(); ) {
+ JsonNode aggregates = metric.get("values");
+ for (Iterator<?> it = aggregates.fieldNames(); it.hasNext(); ) {
String aggregator = (String) it.next();
- Number value = (Number) aggregates.get(aggregator);
+ JsonNode aggregatorValue = aggregates.get(aggregator);
+ if (aggregatorValue == null) {
+ throw new IllegalArgumentException("Value for aggregator '" + aggregator + "' is missing");
+ }
+ Number value = aggregatorValue.numberValue();
+ if (value == null) {
+ throw new IllegalArgumentException("Value for aggregator '" + aggregator + "' is not a number");
+ }
StringBuilder metricName = (new StringBuilder()).append(name).append(".").append(aggregator);
m.add(new Metric(metricName.toString(), value, timestamp, dim, description));
}
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java
index d7576718e8a..cf1eac3c691 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java
@@ -8,13 +8,11 @@ import ai.vespa.metricsproxy.metric.model.json.GenericApplicationModel;
import ai.vespa.metricsproxy.metric.model.json.GenericJsonModel;
import ai.vespa.metricsproxy.metric.model.json.GenericMetrics;
import ai.vespa.metricsproxy.metric.model.json.GenericService;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.yahoo.container.jdisc.RequestHandlerTestDriver;
-import java.util.regex.Pattern;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -24,6 +22,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.Executors;
+import java.util.regex.Pattern;
import static ai.vespa.metricsproxy.TestUtil.getFileContents;
import static ai.vespa.metricsproxy.http.ValuesFetcher.defaultMetricsConsumerId;
@@ -49,6 +48,8 @@ import static org.junit.Assert.fail;
@SuppressWarnings("UnstableApiUsage")
public class ApplicationMetricsHandlerTest {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final String HOST = "localhost";
private static final String URI_BASE = "http://" + HOST;
private static final String METRICS_V1_URI = URI_BASE + METRICS_V1_PATH;
@@ -102,16 +103,16 @@ public class ApplicationMetricsHandlerTest {
@Test
public void v1_response_contains_values_uri() throws Exception {
String response = testDriver.sendRequest(METRICS_V1_URI).readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("resources"));
- JSONArray resources = root.getJSONArray("resources");
- assertEquals(2, resources.length());
+ ArrayNode resources = (ArrayNode) root.get("resources");
+ assertEquals(2, resources.size());
- JSONObject valuesUrl = resources.getJSONObject(0);
- assertEquals(METRICS_VALUES_URI, valuesUrl.getString("url"));
- JSONObject prometheusUrl = resources.getJSONObject(1);
- assertEquals(PROMETHEUS_VALUES_URI, prometheusUrl.getString("url"));
+ JsonNode valuesUrl = resources.get(0);
+ assertEquals(METRICS_VALUES_URI, valuesUrl.get("url").textValue());
+ JsonNode prometheusUrl = resources.get(1);
+ assertEquals(PROMETHEUS_VALUES_URI, prometheusUrl.get("url").textValue());
}
@Ignore
@@ -199,7 +200,7 @@ public class ApplicationMetricsHandlerTest {
@Test
public void invalid_path_yields_error_response() throws Exception {
String response = testDriver.sendRequest(METRICS_V1_URI + "/invalid").readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("error"));
}
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java
index 1c5ce695155..379ef04d38d 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java
@@ -6,9 +6,9 @@ import ai.vespa.metricsproxy.metric.model.json.GenericJsonModel;
import ai.vespa.metricsproxy.metric.model.json.GenericMetrics;
import ai.vespa.metricsproxy.metric.model.json.GenericService;
import ai.vespa.metricsproxy.service.DownService;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import org.json.JSONArray;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import org.junit.Ignore;
import org.junit.Test;
@@ -32,6 +32,8 @@ import static org.junit.Assert.fail;
*/
public abstract class MetricsHandlerTestBase<MODEL> extends HttpHandlerTestBase {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
static String rootUri;
static String valuesUri;
@@ -56,21 +58,21 @@ public abstract class MetricsHandlerTestBase<MODEL> extends HttpHandlerTestBase
@Test
public void invalid_path_yields_error_response() throws Exception {
String response = testDriver.sendRequest(rootUri + "/invalid").readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("error"));
}
@Test
public void root_response_contains_values_uri() throws Exception {
String response = testDriver.sendRequest(rootUri).readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("resources"));
- JSONArray resources = root.getJSONArray("resources");
- assertEquals(1, resources.length());
+ ArrayNode resources = (ArrayNode) root.get("resources");
+ assertEquals(1, resources.size());
- JSONObject valuesUrl = resources.getJSONObject(0);
- assertEquals(valuesUri, valuesUrl.getString("url"));
+ JsonNode valuesUrl = resources.get(0);
+ assertEquals(valuesUri, valuesUrl.get("url").textValue());
}
@Ignore
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java
index a224c4090b3..89186e63b93 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java
@@ -3,9 +3,10 @@ package ai.vespa.metricsproxy.http.prometheus;
import ai.vespa.metricsproxy.http.HttpHandlerTestBase;
import ai.vespa.metricsproxy.service.DummyService;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
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;
@@ -22,6 +23,8 @@ import static org.junit.Assert.assertTrue;
@SuppressWarnings("UnstableApiUsage")
public class PrometheusHandlerTest extends HttpHandlerTestBase {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final String V1_URI = URI_BASE + PrometheusHandler.V1_PATH;
private static final String VALUES_URI = URI_BASE + PrometheusHandler.VALUES_PATH;
@@ -40,14 +43,14 @@ public class PrometheusHandlerTest extends HttpHandlerTestBase {
@Test
public void v1_response_contains_values_uri() throws Exception {
String response = testDriver.sendRequest(V1_URI).readAll();
- JSONObject root = new JSONObject(response);
+ JsonNode root = jsonMapper.readTree(response);
assertTrue(root.has("resources"));
- JSONArray resources = root.getJSONArray("resources");
- assertEquals(1, resources.length());
+ ArrayNode resources = (ArrayNode) root.get("resources");
+ assertEquals(1, resources.size());
- JSONObject valuesUrl = resources.getJSONObject(0);
- assertEquals(VALUES_URI, valuesUrl.getString("url"));
+ JsonNode valuesUrl = resources.get(0);
+ assertEquals(VALUES_URI, valuesUrl.get("url").textValue());
}
@Ignore
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java
index e2ad0ccd504..c2fc23a878d 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java
@@ -3,8 +3,9 @@ package ai.vespa.metricsproxy.node;
import ai.vespa.metricsproxy.metric.model.MetricId;
import ai.vespa.metricsproxy.metric.model.MetricsPacket;
-import org.json.JSONException;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.Test;
import java.util.ArrayList;
@@ -17,10 +18,12 @@ import static org.junit.Assert.assertEquals;
*/
public class NodeMetricGathererTest {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
@Test
- public void testJSONObjectIsCorrectlyConvertedToMetricsPacket() throws JSONException {
+ public void testJSONObjectIsCorrectlyConvertedToMetricsPacket() {
List<MetricsPacket.Builder> builders = new ArrayList<>();
- JSONObject hostLifePacket = generateHostLifePacket();
+ JsonNode hostLifePacket = generateHostLifePacket();
NodeMetricGatherer.addObjectToBuilders(builders, hostLifePacket);
MetricsPacket packet = builders.remove(0).build();
@@ -32,17 +35,17 @@ public class NodeMetricGathererTest {
assertEquals(1l, packet.metrics().get(MetricId.toMetricId("alive")));
}
- private JSONObject generateHostLifePacket() throws JSONException {
+ private JsonNode generateHostLifePacket() {
- JSONObject jsonObject = new JSONObject();
+ ObjectNode jsonObject = jsonMapper.createObjectNode();
jsonObject.put("status_code", 0);
jsonObject.put("status_msg", "OK");
jsonObject.put("timestamp", 123);
jsonObject.put("application", "host_life");
- JSONObject metrics = new JSONObject();
+ ObjectNode metrics = jsonMapper.createObjectNode();
metrics.put("uptime", 12);
metrics.put("alive", 1);
- jsonObject.put("metrics", metrics);
+ jsonObject.set("metrics", metrics);
return jsonObject;
}
}
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java
index 8d5bba77844..70970bfe8da 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java
@@ -5,17 +5,18 @@ import ai.vespa.metricsproxy.metric.Metric;
import ai.vespa.metricsproxy.metric.Metrics;
import ai.vespa.metricsproxy.metric.model.ConsumerId;
import ai.vespa.metricsproxy.service.VespaService;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.yahoo.jrt.Request;
import com.yahoo.jrt.Spec;
import com.yahoo.jrt.StringValue;
import com.yahoo.jrt.Supervisor;
import com.yahoo.jrt.Target;
import com.yahoo.jrt.Transport;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import org.junit.Test;
+import java.io.IOException;
import java.util.List;
import static ai.vespa.metricsproxy.TestUtil.getFileContents;
@@ -40,6 +41,8 @@ import static org.junit.Assert.assertTrue;
*/
public class RpcMetricsTest {
+ private static final ObjectMapper jsonMapper = new ObjectMapper();
+
private static final String METRICS_RESPONSE = getFileContents("metrics-storage-simple.json").trim();
private static final String EXTRA_APP = "extra";
@@ -67,9 +70,9 @@ public class RpcMetricsTest {
String allServicesResponse = getMetricsForYamas(ALL_SERVICES, rpcClient).trim();
// Verify that application is used as serviceId, and that metric exists.
- JSONObject extraMetrics = findExtraMetricsObject(allServicesResponse);
- assertThat(extraMetrics.getJSONObject("metrics").getInt("foo.count"), is(3));
- assertThat(extraMetrics.getJSONObject("dimensions").getString("role"), is("extra-role"));
+ JsonNode extraMetrics = findExtraMetricsObject(allServicesResponse);
+ assertThat(extraMetrics.get("metrics").get("foo.count").intValue(), is(3));
+ assertThat(extraMetrics.get("dimensions").get("role").textValue(), is("extra-role"));
}
}
}
@@ -85,7 +88,7 @@ public class RpcMetricsTest {
// Verify that no extra metrics exists
String allServicesResponse = getMetricsForYamas(ALL_SERVICES, rpcClient).trim();
- JSONObject extraMetrics = findExtraMetricsObject(allServicesResponse);
+ JsonNode extraMetrics = findExtraMetricsObject(allServicesResponse);
assertEquals(extraMetrics.toString(), "{}");
}
}
@@ -130,28 +133,28 @@ public class RpcMetricsTest {
}
}
- private static void verifyMetricsFromRpcRequest(VespaService service, RpcClient client) throws JSONException {
+ private static void verifyMetricsFromRpcRequest(VespaService service, RpcClient client) throws IOException {
String jsonResponse = getMetricsForYamas(service.getMonitoringName(), client).trim();
- JSONArray metrics = new JSONObject(jsonResponse).getJSONArray("metrics");
- assertThat("Expected 3 metric messages", metrics.length(), is(3));
- for (int i = 0; i < metrics.length() - 1; i++) { // The last "metric message" contains only status code/message
- JSONObject jsonObject = metrics.getJSONObject(i);
+ ArrayNode metrics = (ArrayNode) jsonMapper.readTree(jsonResponse).get("metrics");
+ assertThat("Expected 3 metric messages", metrics.size(), is(3));
+ for (int i = 0; i < metrics.size() - 1; i++) { // The last "metric message" contains only status code/message
+ JsonNode jsonObject = metrics.get(i);
assertFalse(jsonObject.has("status_code"));
assertFalse(jsonObject.has("status_msg"));
- assertThat(jsonObject.getJSONObject("dimensions").getString("foo"), is("bar"));
- assertThat(jsonObject.getJSONObject("dimensions").getString("bar"), is("foo"));
- assertThat(jsonObject.getJSONObject("dimensions").getString("serviceDim"), is("serviceDimValue"));
- assertThat(jsonObject.getJSONObject("routing").getJSONObject("yamas").getJSONArray("namespaces").length(), is(1));
- if (jsonObject.getJSONObject("metrics").has("foo_count")) {
- assertThat(jsonObject.getJSONObject("metrics").getInt("foo_count"), is(1));
- assertThat(jsonObject.getJSONObject("routing").getJSONObject("yamas").getJSONArray("namespaces").get(0), is(vespaMetricsConsumerId.id));
+ assertThat(jsonObject.get("dimensions").get("foo").textValue(), is("bar"));
+ assertThat(jsonObject.get("dimensions").get("bar").textValue(), is("foo"));
+ assertThat(jsonObject.get("dimensions").get("serviceDim").textValue(), is("serviceDimValue"));
+ assertThat(jsonObject.get("routing").get("yamas").get("namespaces").size(), is(1));
+ if (jsonObject.get("metrics").has("foo_count")) {
+ assertThat(jsonObject.get("metrics").get("foo_count").intValue(), is(1));
+ assertThat(jsonObject.get("routing").get("yamas").get("namespaces").get(0).textValue(), is(vespaMetricsConsumerId.id));
} else {
- assertThat(jsonObject.getJSONObject("metrics").getInt("foo.count"), is(1));
- assertThat(jsonObject.getJSONObject("routing").getJSONObject("yamas").getJSONArray("namespaces").get(0), is(CUSTOM_CONSUMER_ID.id));
+ assertThat(jsonObject.get("metrics").get("foo.count").intValue(), is(1));
+ assertThat(jsonObject.get("routing").get("yamas").get("namespaces").get(0).textValue(), is(CUSTOM_CONSUMER_ID.id));
}
}
- verifyStatusMessage(metrics.getJSONObject(metrics.length() - 1));
+ verifyStatusMessage(metrics.get(metrics.size() - 1));
}
private void verfiyMetricsFromServiceObject(VespaService service) {
@@ -166,15 +169,15 @@ public class RpcMetricsTest {
assertThat("Metric foo did not contain correct dimension for key = bar", foo.getDimensions().get(toDimensionId("bar")), is("foo"));
}
- private void verifyMetricsFromRpcRequestForAllServices(RpcClient client) throws JSONException {
+ private void verifyMetricsFromRpcRequestForAllServices(RpcClient client) throws IOException {
// Verify that metrics for all services can be retrieved in one request.
String allServicesResponse = getMetricsForYamas(ALL_SERVICES, client).trim();
- JSONArray allServicesMetrics = new JSONObject(allServicesResponse).getJSONArray("metrics");
- assertThat(allServicesMetrics.length(), is(5));
+ ArrayNode allServicesMetrics = (ArrayNode) jsonMapper.readTree(allServicesResponse).get("metrics");
+ assertThat(allServicesMetrics.size(), is(5));
}
@Test
- public void testGetAllMetricNames() throws Exception {
+ public void testGetAllMetricNames() {
try (IntegrationTester tester = new IntegrationTester()) {
tester.httpServer().setResponse(METRICS_RESPONSE);
@@ -205,14 +208,14 @@ public class RpcMetricsTest {
invoke(req, rpcClient, false);
}
- private JSONObject findExtraMetricsObject(String jsonResponse) throws JSONException {
- JSONArray metrics = new JSONObject(jsonResponse).getJSONArray("metrics");
- for (int i = 0; i < metrics.length(); i++) {
- JSONObject jsonObject = metrics.getJSONObject(i);
+ private JsonNode findExtraMetricsObject(String jsonResponse) throws IOException {
+ ArrayNode metrics = (ArrayNode) jsonMapper.readTree(jsonResponse).get("metrics");
+ for (int i = 0; i < metrics.size(); i++) {
+ JsonNode jsonObject = metrics.get(i);
assertTrue(jsonObject.has("application"));
- if (jsonObject.getString("application").equals(EXTRA_APP)) return jsonObject;
+ if (jsonObject.get("application").textValue().equals(EXTRA_APP)) return jsonObject;
}
- return new JSONObject();
+ return jsonMapper.createObjectNode();
}
private static String getMetricsForYamas(String service, RpcClient client) {
@@ -250,12 +253,12 @@ public class RpcMetricsTest {
return returnValue;
}
- private static void verifyStatusMessage(JSONObject jsonObject) throws JSONException {
- assertThat(jsonObject.getInt("status_code"), is(0));
- assertThat(jsonObject.getString("status_msg"), notNullValue());
- assertThat(jsonObject.getString("application"), notNullValue());
- assertThat(jsonObject.getString("routing"), notNullValue());
- assertThat(jsonObject.length(), is(4));
+ private static void verifyStatusMessage(JsonNode jsonObject) {
+ assertThat(jsonObject.get("status_code").intValue(), is(0));
+ assertThat(jsonObject.get("status_msg").textValue(), notNullValue());
+ assertThat(jsonObject.get("application").textValue(), notNullValue());
+ assertThat(jsonObject.get("routing"), notNullValue());
+ assertThat(jsonObject.size(), is(4));
}
}
diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java
index 0d53f988ac7..7ff179e5528 100644
--- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java
+++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java
@@ -2,7 +2,6 @@
package ai.vespa.metricsproxy.service;
import ai.vespa.metricsproxy.metric.Metric;
-import org.json.JSONException;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -37,7 +36,7 @@ public class ContainerServiceTest {
}
@Test
- public void testMultipleQueryDimensions() throws JSONException {
+ public void testMultipleQueryDimensions() {
int count = 0;
VespaService service = VespaService.create("service1", "id", httpServer.port());
for (Metric m : service.getMetrics().getMetrics()) {