| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.metrics.dropwizard; |
| |
| import com.codahale.metrics.Counter; |
| import com.codahale.metrics.Gauge; |
| import com.codahale.metrics.Histogram; |
| import com.codahale.metrics.Meter; |
| import com.codahale.metrics.Metric; |
| import com.codahale.metrics.Snapshot; |
| import com.codahale.metrics.Timer; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.gerrit.common.Nullable; |
| import com.google.gerrit.metrics.Description; |
| import com.google.gerrit.metrics.Field; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.function.Function; |
| |
| class MetricJson { |
| String description; |
| String unit; |
| Boolean constant; |
| Boolean rate; |
| Boolean gauge; |
| Boolean cumulative; |
| |
| Long count; |
| Object value; |
| |
| Double rate_1m; |
| Double rate_5m; |
| Double rate_15m; |
| Double rate_mean; |
| |
| Double p50; |
| Double p75; |
| Double p95; |
| Double p98; |
| Double p99; |
| Double p99_9; |
| |
| Double min; |
| Double avg; |
| Double max; |
| Double sum; |
| Double std_dev; |
| |
| List<FieldJson> fields; |
| Map<String, Object> buckets; |
| |
| MetricJson(Metric metric, ImmutableMap<String, String> atts, boolean dataOnly) { |
| if (!dataOnly) { |
| description = atts.get(Description.DESCRIPTION); |
| unit = atts.get(Description.UNIT); |
| constant = toBool(atts, Description.CONSTANT); |
| rate = toBool(atts, Description.RATE); |
| gauge = toBool(atts, Description.GAUGE); |
| cumulative = toBool(atts, Description.CUMULATIVE); |
| } |
| init(metric, atts); |
| } |
| |
| private void init(Metric metric, ImmutableMap<String, String> atts) { |
| if (metric instanceof BucketedMetric) { |
| BucketedMetric m = (BucketedMetric) metric; |
| if (m.getTotal() != null) { |
| init(m.getTotal(), atts); |
| } |
| |
| Field<?>[] fieldList = m.getFields(); |
| fields = new ArrayList<>(fieldList.length); |
| for (Field<?> f : fieldList) { |
| fields.add(new FieldJson(f)); |
| } |
| buckets = makeBuckets(fieldList, m.getCells(), atts); |
| |
| } else if (metric instanceof Counter) { |
| Counter c = (Counter) metric; |
| count = c.getCount(); |
| |
| } else if (metric instanceof Gauge) { |
| Gauge<?> g = (Gauge<?>) metric; |
| value = g.getValue(); |
| |
| } else if (metric instanceof Meter) { |
| Meter m = (Meter) metric; |
| count = m.getCount(); |
| rate_1m = m.getOneMinuteRate(); |
| rate_5m = m.getFiveMinuteRate(); |
| rate_15m = m.getFifteenMinuteRate(); |
| |
| } else if (metric instanceof Timer) { |
| Timer m = (Timer) metric; |
| Snapshot s = m.getSnapshot(); |
| count = m.getCount(); |
| rate_1m = m.getOneMinuteRate(); |
| rate_5m = m.getFiveMinuteRate(); |
| rate_15m = m.getFifteenMinuteRate(); |
| |
| double div = Description.getTimeUnit(atts.get(Description.UNIT)).toNanos(1); |
| p50 = s.getMedian() / div; |
| p75 = s.get75thPercentile() / div; |
| p95 = s.get95thPercentile() / div; |
| p98 = s.get98thPercentile() / div; |
| p99 = s.get99thPercentile() / div; |
| p99_9 = s.get999thPercentile() / div; |
| |
| min = s.getMin() / div; |
| max = s.getMax() / div; |
| std_dev = s.getStdDev() / div; |
| |
| } else if (metric instanceof Histogram) { |
| Histogram m = (Histogram) metric; |
| Snapshot s = m.getSnapshot(); |
| count = m.getCount(); |
| |
| p50 = s.getMedian(); |
| p75 = s.get75thPercentile(); |
| p95 = s.get95thPercentile(); |
| p98 = s.get98thPercentile(); |
| p99 = s.get99thPercentile(); |
| p99_9 = s.get999thPercentile(); |
| |
| min = (double) s.getMin(); |
| avg = s.getMean(); |
| max = (double) s.getMax(); |
| sum = s.getMean() * m.getCount(); |
| std_dev = s.getStdDev(); |
| } |
| } |
| |
| @Nullable |
| private static Boolean toBool(ImmutableMap<String, String> atts, String key) { |
| return Description.TRUE_VALUE.equals(atts.get(key)) ? true : null; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static Map<String, Object> makeBuckets( |
| Field<?>[] fields, Map<?, Metric> metrics, ImmutableMap<String, String> atts) { |
| if (fields.length == 1) { |
| Function<Object, String> fmt = (Function<Object, String>) fields[0].formatter(); |
| Map<String, Object> out = new TreeMap<>(); |
| for (Map.Entry<?, Metric> e : metrics.entrySet()) { |
| out.put(fmt.apply(e.getKey()), new MetricJson(e.getValue(), atts, true)); |
| } |
| return out; |
| } |
| |
| Map<String, Object> out = new TreeMap<>(); |
| for (Map.Entry<?, Metric> e : metrics.entrySet()) { |
| ImmutableList<Object> keys = (ImmutableList<Object>) e.getKey(); |
| Map<String, Object> dst = out; |
| |
| for (int i = 0; i < fields.length - 1; i++) { |
| Function<Object, String> fmt = (Function<Object, String>) fields[i].formatter(); |
| String key = fmt.apply(keys.get(i)); |
| Map<String, Object> t = (Map<String, Object>) dst.get(key); |
| if (t == null) { |
| t = new TreeMap<>(); |
| dst.put(key, t); |
| } |
| dst = t; |
| } |
| |
| Function<Object, String> fmt = |
| (Function<Object, String>) fields[fields.length - 1].formatter(); |
| dst.put(fmt.apply(keys.get(fields.length - 1)), new MetricJson(e.getValue(), atts, true)); |
| } |
| return out; |
| } |
| |
| static class FieldJson { |
| String name; |
| String type; |
| String description; |
| |
| FieldJson(Field<?> field) { |
| this.name = field.name(); |
| this.description = field.description().orElse(null); |
| this.type = |
| Enum.class.isAssignableFrom(field.valueType()) ? field.valueType().getSimpleName() : null; |
| } |
| } |
| } |