1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.metrics2.lib;
20
21 import com.google.common.annotations.VisibleForTesting;
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.hadoop.classification.InterfaceAudience;
24 import org.apache.hadoop.classification.InterfaceStability;
25 import org.apache.hadoop.metrics2.MetricHistogram;
26 import org.apache.hadoop.metrics2.MetricsExecutor;
27 import org.apache.hadoop.metrics2.MetricsInfo;
28 import org.apache.hadoop.metrics2.MetricsRecordBuilder;
29 import org.apache.hadoop.metrics2.util.MetricQuantile;
30 import org.apache.hadoop.metrics2.util.MetricSampleQuantiles;
31
32 import java.io.IOException;
33 import java.util.Map;
34 import java.util.concurrent.TimeUnit;
35
36 import static org.apache.hadoop.metrics2.lib.Interns.info;
37
38
39
40
41
42
43 @InterfaceAudience.Public
44 @InterfaceStability.Evolving
45 public class MetricMutableQuantiles extends MutableMetric implements MetricHistogram {
46
47 static final MetricQuantile[] quantiles = {new MetricQuantile(0.50, 0.050),
48 new MetricQuantile(0.75, 0.025), new MetricQuantile(0.90, 0.010),
49 new MetricQuantile(0.95, 0.005), new MetricQuantile(0.99, 0.001)};
50
51 private final MetricsInfo numInfo;
52 private final MetricsInfo[] quantileInfos;
53 private final int interval;
54
55 private MetricSampleQuantiles estimator;
56 private long previousCount = 0;
57 private MetricsExecutor executor;
58
59
60 @VisibleForTesting
61 protected Map<MetricQuantile, Long> previousSnapshot = null;
62
63
64
65
66
67
68
69
70
71
72
73 public MetricMutableQuantiles(String name, String description, String sampleName,
74 String valueName, int interval) {
75 String ucName = StringUtils.capitalize(name);
76 String usName = StringUtils.capitalize(sampleName);
77 String uvName = StringUtils.capitalize(valueName);
78 String desc = StringUtils.uncapitalize(description);
79 String lsName = StringUtils.uncapitalize(sampleName);
80 String lvName = StringUtils.uncapitalize(valueName);
81
82 numInfo = info(ucName + "Num" + usName, String.format(
83 "Number of %s for %s with %ds interval", lsName, desc, interval));
84
85 quantileInfos = new MetricsInfo[quantiles.length];
86 String nameTemplate = ucName + "%dthPercentile" + interval + "sInterval"
87 + uvName;
88 String descTemplate = "%d percentile " + lvName + " with " + interval
89 + " second interval for " + desc;
90 for (int i = 0; i < quantiles.length; i++) {
91 int percentile = (int) (100 * quantiles[i].quantile);
92 quantileInfos[i] = info(String.format(nameTemplate, percentile),
93 String.format(descTemplate, percentile));
94 }
95
96 estimator = new MetricSampleQuantiles(quantiles);
97 executor = new MetricsExecutorImpl();
98 this.interval = interval;
99 executor.getExecutor().scheduleAtFixedRate(new RolloverSample(this),
100 interval,
101 interval,
102 TimeUnit.SECONDS);
103 }
104
105 @Override
106 public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) {
107 if (all || changed()) {
108 builder.addGauge(numInfo, previousCount);
109 for (int i = 0; i < quantiles.length; i++) {
110 long newValue = 0;
111
112 if (previousSnapshot != null) {
113 newValue = previousSnapshot.get(quantiles[i]);
114 }
115 builder.addGauge(quantileInfos[i], newValue);
116 }
117 if (changed()) {
118 clearChanged();
119 }
120 }
121 }
122
123 public synchronized void add(long value) {
124 estimator.insert(value);
125 }
126
127 public int getInterval() {
128 return interval;
129 }
130
131
132 private static class RolloverSample implements Runnable {
133
134 MetricMutableQuantiles parent;
135
136 public RolloverSample(MetricMutableQuantiles parent) {
137 this.parent = parent;
138 }
139
140 @Override
141 public void run() {
142 synchronized (parent) {
143 try {
144 parent.previousCount = parent.estimator.getCount();
145 parent.previousSnapshot = parent.estimator.snapshot();
146 } catch (IOException e) {
147
148 parent.previousCount = 0;
149 parent.previousSnapshot = null;
150 }
151 parent.estimator.clear();
152 }
153 parent.setChanged();
154 }
155
156 }
157 }