blob: 27e93772296a855edbd9efe36df67bea2d8c8c16 [file] [log] [blame]
// 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;
}
}
}