aboutsummaryrefslogtreecommitdiffstats
path: root/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc
diff options
context:
space:
mode:
Diffstat (limited to 'simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc')
-rw-r--r--simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/JdiscMetricsFactory.java61
-rw-r--r--simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SimpleMetricConsumer.java55
-rw-r--r--simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SnapshotConverter.java212
-rw-r--r--simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/package-info.java10
4 files changed, 338 insertions, 0 deletions
diff --git a/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/JdiscMetricsFactory.java b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/JdiscMetricsFactory.java
new file mode 100644
index 00000000000..f5208b2226c
--- /dev/null
+++ b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/JdiscMetricsFactory.java
@@ -0,0 +1,61 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.metrics.simple.jdisc;
+
+import java.io.PrintStream;
+import java.util.logging.Logger;
+
+import com.yahoo.container.jdisc.MetricConsumerFactory;
+import com.yahoo.container.jdisc.state.MetricSnapshot;
+import com.yahoo.container.jdisc.state.SnapshotProvider;
+import com.yahoo.jdisc.application.MetricConsumer;
+import com.yahoo.metrics.simple.Bucket;
+import com.yahoo.metrics.simple.MetricReceiver;
+
+/**
+ * A factory for all the JDisc API classes.
+ *
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ */
+public class JdiscMetricsFactory implements MetricConsumerFactory, SnapshotProvider {
+ private static final Logger log = Logger.getLogger(JdiscMetricsFactory.class.getName());
+ private final SimpleMetricConsumer metricInstance;
+ private final MetricReceiver metricReceiver;
+
+ public JdiscMetricsFactory(MetricReceiver receiver) {
+ this.metricReceiver = receiver;
+ this.metricInstance = new SimpleMetricConsumer(receiver);
+ }
+
+ @Override
+ public MetricConsumer newInstance() {
+ // the underlying implementation is thread safe anyway to allow for stand-alone use
+ return metricInstance;
+ }
+
+
+ @Override
+ public MetricSnapshot latestSnapshot() {
+ Bucket curr = metricReceiver.getSnapshot();
+ if (curr == null) {
+ log.warning("no snapshot from instance of " + metricInstance.getClass());
+ return null;
+ } else {
+ SnapshotConverter converter = new SnapshotConverter(curr);
+ return converter.convert();
+ }
+ }
+
+ @Override
+ public void histogram(PrintStream output) {
+ Bucket curr = metricReceiver.getSnapshot();
+ if (curr == null) {
+ log.warning("no snapshot from instance of " + metricInstance.getClass());
+ return;
+ } else {
+ SnapshotConverter converter = new SnapshotConverter(curr);
+ converter.outputHistograms(output);
+ return;
+ }
+ }
+
+}
diff --git a/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SimpleMetricConsumer.java b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SimpleMetricConsumer.java
new file mode 100644
index 00000000000..7f5571418fe
--- /dev/null
+++ b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SimpleMetricConsumer.java
@@ -0,0 +1,55 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.metrics.simple.jdisc;
+
+import java.util.Map;
+
+import com.yahoo.jdisc.Metric.Context;
+import com.yahoo.jdisc.application.MetricConsumer;
+import com.yahoo.metrics.simple.Identifier;
+import com.yahoo.metrics.simple.Measurement;
+import com.yahoo.metrics.simple.Point;
+import com.yahoo.metrics.simple.MetricReceiver;
+import com.yahoo.metrics.simple.Sample;
+import com.yahoo.metrics.simple.UntypedMetric.AssumedType;
+
+/**
+ * The single user facing part of the JDisc interfaces of simple metrics.
+ *
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ */
+public class SimpleMetricConsumer implements MetricConsumer {
+
+ private final MetricReceiver receiver;
+
+ public SimpleMetricConsumer(MetricReceiver receiver) {
+ this.receiver = receiver;
+ }
+
+ @Override
+ public void set(String key, Number val, Context ctx) {
+ receiver.update(new Sample(new Measurement(val), new Identifier(key, getSimpleCoordinate(ctx)), AssumedType.GAUGE));
+ }
+
+ @Override
+ public void add(String key, Number val, Context ctx) {
+ receiver.update(new Sample(new Measurement(val), new Identifier(key, getSimpleCoordinate(ctx)), AssumedType.COUNTER));
+ }
+
+ private Point getSimpleCoordinate(Context ctx) {
+ if (ctx instanceof Point) {
+ return (Point) ctx;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Context createContext(Map<String, ?> properties) {
+ if (properties == null) {
+ return null;
+ } else {
+ return new Point(properties);
+ }
+ }
+
+}
diff --git a/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SnapshotConverter.java b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SnapshotConverter.java
new file mode 100644
index 00000000000..6d3b6ad6243
--- /dev/null
+++ b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/SnapshotConverter.java
@@ -0,0 +1,212 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.metrics.simple.jdisc;
+
+import java.io.PrintStream;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import org.HdrHistogram.DoubleHistogram;
+
+import com.yahoo.collections.Tuple2;
+import com.yahoo.container.jdisc.state.*;
+import com.yahoo.metrics.simple.Bucket;
+import com.yahoo.metrics.simple.Identifier;
+import com.yahoo.metrics.simple.Point;
+import com.yahoo.metrics.simple.UntypedMetric;
+import com.yahoo.metrics.simple.Value;
+import com.yahoo.text.JSON;
+
+/**
+ * Convert simple metrics snapshots into jdisc state snapshots.
+ *
+ * @author arnej27959
+ */
+class SnapshotConverter {
+ final Bucket snapshot;
+ final Map<Point, Map<String, MetricValue>> perPointData = new HashMap<>();
+ private static final char[] DIGITS = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ private Map<String, MetricValue> getMap(Point point) {
+ if (! perPointData.containsKey(point)) {
+ perPointData.put(point, new HashMap<String, MetricValue>());
+ }
+ return perPointData.get(point);
+ }
+
+ public SnapshotConverter(Bucket snapshot) {
+ this.snapshot = snapshot;
+ }
+
+ static MetricDimensions convert(Point p) {
+ if (p == null) {
+ return StateMetricContext.newInstance(null);
+ }
+ List<String> dimensions = p.dimensions();
+ List<Value> location = p.location();
+ Map<String, Object> pointWrapper = new HashMap<>(dimensions.size());
+ for (int i = 0; i < dimensions.size(); ++i) {
+ pointWrapper.put(dimensions.get(i), valueAsString(location.get(i)));
+ }
+ return StateMetricContext.newInstance(pointWrapper);
+ }
+
+ // TODO: just a compatibility wrapper, should be removed ASAP
+ private static Object valueAsString(Value value) {
+ switch (value.getType()) {
+ case STRING:
+ return value.stringValue();
+ case LONG:
+ return Long.valueOf(value.longValue());
+ case DOUBLE:
+ return Double.valueOf(value.doubleValue());
+ default:
+ throw new IllegalStateException("simplemetrics impl is out of sync with itself, please file a ticket.");
+ }
+ }
+
+
+ static MetricValue convert(UntypedMetric val) {
+ if (val.isCounter()) {
+ return CountMetric.newInstance(val.getCount());
+ } else {
+ if (val.getHistogram() == null) {
+ return GaugeMetric.newInstance(val.getLast(), val.getMax(), val.getMin(), val.getSum(), val.getCount());
+ } else {
+ return GaugeMetric.newInstance(val.getLast(), val.getMax(), val.getMin(), val.getSum(), val.getCount(),
+ Optional.of(buildPercentileList(val.getHistogram())));
+ }
+ }
+ }
+
+ private static List<Tuple2<String, Double>> buildPercentileList(DoubleHistogram histogram) {
+ final List<Tuple2<String, Double>> prefixAndValues = new ArrayList<>(2);
+ prefixAndValues.add(new Tuple2<>("95", histogram.getValueAtPercentile(95.0d)));
+ prefixAndValues.add(new Tuple2<>("99", histogram.getValueAtPercentile(99.0d)));
+ return prefixAndValues;
+ }
+
+ MetricSnapshot convert() {
+ for (Map.Entry<Identifier, UntypedMetric> entry : snapshot.entrySet()) {
+ Identifier ident = entry.getKey();
+ getMap(ident.getLocation()).put(ident.getName(), convert(entry.getValue()));
+ }
+ Map<MetricDimensions, MetricSet> data = new HashMap<>();
+ for (Map.Entry<Point, Map<String, MetricValue>> entry : perPointData.entrySet()) {
+ data.put(convert(entry.getKey()), new MetricSet(entry.getValue()));
+ }
+ return new MetricSnapshot(snapshot.getFromMillis(),
+ snapshot.getToMillis(),
+ TimeUnit.MILLISECONDS,
+ data);
+ }
+
+ void outputHistograms(PrintStream output) {
+ boolean gotHistogram = false;
+ for (Map.Entry<Identifier, UntypedMetric> entry : snapshot.entrySet()) {
+ if (entry.getValue().getHistogram() == null) {
+ continue;
+ }
+ gotHistogram = true;
+ DoubleHistogram histogram = entry.getValue().getHistogram();
+ Identifier id = entry.getKey();
+ String metricIdentifier = getIdentifierString(id);
+ output.println("# start of metric " + metricIdentifier);
+ histogram.outputPercentileDistribution(output, 4, 1.0d, true);
+ output.println("# end of metric " + metricIdentifier);
+ }
+ if (!gotHistogram) {
+ output.println("# No histograms currently available.");
+ }
+ }
+
+ private String getIdentifierString(Identifier id) {
+ StringBuilder buffer = new StringBuilder();
+ Point location = id.getLocation();
+ buffer.append(id.getName());
+ if (location != null) {
+ buffer.append(", dimensions: { ");
+ Iterator<String> dimensions = location.dimensions().iterator();
+ Iterator<Value> values = location.location().iterator();
+ boolean firstDimension = true;
+ while (dimensions.hasNext() && values.hasNext()) {
+
+ if (firstDimension) {
+ firstDimension = false;
+ } else {
+ buffer.append(", ");
+ }
+ serializeSingleDimension(buffer, dimensions.next(), values.next());
+ }
+ buffer.append(" }");
+ }
+ return buffer.toString();
+
+ }
+
+ private void serializeSingleDimension(StringBuilder buffer, final String dimensionName, Value dimensionValue) {
+ buffer.append('"');
+ escape(dimensionName, buffer);
+ buffer.append("\": ");
+ switch (dimensionValue.getType()) {
+ case LONG:
+ buffer.append(Long.toString(dimensionValue.longValue()));
+ break;
+ case DOUBLE:
+ buffer.append(Double.toString(dimensionValue.doubleValue()));
+ break;
+ case STRING:
+ buffer.append('"');
+ escape(dimensionValue.stringValue(), buffer);
+ buffer.append('"');
+ break;
+ default:
+ buffer.append("\"Unknown type for this dimension, this is a bug.\"");
+ break;
+ }
+ }
+
+ private void escape(final String in, final StringBuilder target) {
+ for (final char c : in.toCharArray()) {
+ switch (c) {
+ case ('"'):
+ target.append("\\\"");
+ break;
+ case ('\\'):
+ target.append("\\\\");
+ break;
+ case ('\b'):
+ target.append("\\b");
+ break;
+ case ('\f'):
+ target.append("\\f");
+ break;
+ case ('\n'):
+ target.append("\\n");
+ break;
+ case ('\r'):
+ target.append("\\r");
+ break;
+ case ('\t'):
+ target.append("\\t");
+ break;
+ default:
+ if (c < 32) {
+ target.append("\\u").append(fourDigitHexString(c));
+ } else {
+ target.append(c);
+ }
+ break;
+ }
+ }
+ }
+
+ private static char[] fourDigitHexString(final char c) {
+ final char[] hex = new char[4];
+ int in = ((c) & 0xFFFF);
+ for (int i = 3; i >= 0; --i) {
+ hex[i] = DIGITS[in & 0xF];
+ in >>>= 4;
+ }
+ return hex;
+ }
+}
diff --git a/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/package-info.java b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/package-info.java
new file mode 100644
index 00000000000..4d34244bec0
--- /dev/null
+++ b/simplemetrics/src/main/java/com/yahoo/metrics/simple/jdisc/package-info.java
@@ -0,0 +1,10 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * JDisc metrics API for simple metrics implementation.
+ *
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ */
+@ExportPackage
+package com.yahoo.metrics.simple.jdisc;
+
+import com.yahoo.osgi.annotation.ExportPackage;