diff options
Diffstat (limited to 'container-core/src/main/java/com/yahoo/container/jdisc')
7 files changed, 148 insertions, 204 deletions
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; |