001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.apache.hadoop.metrics2.lib;
020
021 import java.util.Collection;
022 import java.util.Map;
023
024 import com.google.common.collect.Maps;
025 import com.google.common.base.Objects;
026
027 import org.apache.hadoop.classification.InterfaceAudience;
028 import org.apache.hadoop.classification.InterfaceStability;
029 import org.apache.hadoop.metrics2.MetricsInfo;
030 import org.apache.hadoop.metrics2.MetricsException;
031 import org.apache.hadoop.metrics2.MetricsRecordBuilder;
032 import org.apache.hadoop.metrics2.MetricsTag;
033 import org.apache.hadoop.metrics2.impl.MsInfo;
034
035 /**
036 * An optional metrics registry class for creating and maintaining a
037 * collection of MetricsMutables, making writing metrics source easier.
038 */
039 @InterfaceAudience.Public
040 @InterfaceStability.Evolving
041 public class MetricsRegistry {
042 private final Map<String, MutableMetric> metricsMap = Maps.newLinkedHashMap();
043 private final Map<String, MetricsTag> tagsMap = Maps.newLinkedHashMap();
044 private final MetricsInfo metricsInfo;
045
046 /**
047 * Construct the registry with a record name
048 * @param name of the record of the metrics
049 */
050 public MetricsRegistry(String name) {
051 metricsInfo = Interns.info(name, name);
052 }
053
054 /**
055 * Construct the registry with a metadata object
056 * @param info the info object for the metrics record/group
057 */
058 public MetricsRegistry(MetricsInfo info) {
059 metricsInfo = info;
060 }
061
062 /**
063 * @return the info object of the metrics registry
064 */
065 public MetricsInfo info() {
066 return metricsInfo;
067 }
068
069 /**
070 * Get a metric by name
071 * @param name of the metric
072 * @return the metric object
073 */
074 public synchronized MutableMetric get(String name) {
075 return metricsMap.get(name);
076 }
077
078 /**
079 * Get a tag by name
080 * @param name of the tag
081 * @return the tag object
082 */
083 public synchronized MetricsTag getTag(String name) {
084 return tagsMap.get(name);
085 }
086
087 /**
088 * Create a mutable integer counter
089 * @param name of the metric
090 * @param desc metric description
091 * @param iVal initial value
092 * @return a new counter object
093 */
094 public MutableCounterInt newCounter(String name, String desc, int iVal) {
095 return newCounter(Interns.info(name, desc), iVal);
096 }
097
098 /**
099 * Create a mutable integer counter
100 * @param info metadata of the metric
101 * @param iVal initial value
102 * @return a new counter object
103 */
104 public synchronized MutableCounterInt newCounter(MetricsInfo info, int iVal) {
105 checkMetricName(info.name());
106 MutableCounterInt ret = new MutableCounterInt(info, iVal);
107 metricsMap.put(info.name(), ret);
108 return ret;
109 }
110
111 /**
112 * Create a mutable long integer counter
113 * @param name of the metric
114 * @param desc metric description
115 * @param iVal initial value
116 * @return a new counter object
117 */
118 public MutableCounterLong newCounter(String name, String desc, long iVal) {
119 return newCounter(Interns.info(name, desc), iVal);
120 }
121
122 /**
123 * Create a mutable long integer counter
124 * @param info metadata of the metric
125 * @param iVal initial value
126 * @return a new counter object
127 */
128 public synchronized
129 MutableCounterLong newCounter(MetricsInfo info, long iVal) {
130 checkMetricName(info.name());
131 MutableCounterLong ret = new MutableCounterLong(info, iVal);
132 metricsMap.put(info.name(), ret);
133 return ret;
134 }
135
136 /**
137 * Create a mutable integer gauge
138 * @param name of the metric
139 * @param desc metric description
140 * @param iVal initial value
141 * @return a new gauge object
142 */
143 public MutableGaugeInt newGauge(String name, String desc, int iVal) {
144 return newGauge(Interns.info(name, desc), iVal);
145 }
146 /**
147 * Create a mutable integer gauge
148 * @param info metadata of the metric
149 * @param iVal initial value
150 * @return a new gauge object
151 */
152 public synchronized MutableGaugeInt newGauge(MetricsInfo info, int iVal) {
153 checkMetricName(info.name());
154 MutableGaugeInt ret = new MutableGaugeInt(info, iVal);
155 metricsMap.put(info.name(), ret);
156 return ret;
157 }
158
159 /**
160 * Create a mutable long integer gauge
161 * @param name of the metric
162 * @param desc metric description
163 * @param iVal initial value
164 * @return a new gauge object
165 */
166 public MutableGaugeLong newGauge(String name, String desc, long iVal) {
167 return newGauge(Interns.info(name, desc), iVal);
168 }
169
170 /**
171 * Create a mutable long integer gauge
172 * @param info metadata of the metric
173 * @param iVal initial value
174 * @return a new gauge object
175 */
176 public synchronized MutableGaugeLong newGauge(MetricsInfo info, long iVal) {
177 checkMetricName(info.name());
178 MutableGaugeLong ret = new MutableGaugeLong(info, iVal);
179 metricsMap.put(info.name(), ret);
180 return ret;
181 }
182
183 /**
184 * Create a mutable metric with stats
185 * @param name of the metric
186 * @param desc metric description
187 * @param sampleName of the metric (e.g., "Ops")
188 * @param valueName of the metric (e.g., "Time" or "Latency")
189 * @param extended produce extended stat (stdev, min/max etc.) if true.
190 * @return a new mutable stat metric object
191 */
192 public synchronized MutableStat newStat(String name, String desc,
193 String sampleName, String valueName, boolean extended) {
194 checkMetricName(name);
195 MutableStat ret =
196 new MutableStat(name, desc, sampleName, valueName, extended);
197 metricsMap.put(name, ret);
198 return ret;
199 }
200
201 /**
202 * Create a mutable metric with stats
203 * @param name of the metric
204 * @param desc metric description
205 * @param sampleName of the metric (e.g., "Ops")
206 * @param valueName of the metric (e.g., "Time" or "Latency")
207 * @return a new mutable metric object
208 */
209 public MutableStat newStat(String name, String desc,
210 String sampleName, String valueName) {
211 return newStat(name, desc, sampleName, valueName, false);
212 }
213
214 /**
215 * Create a mutable rate metric
216 * @param name of the metric
217 * @return a new mutable metric object
218 */
219 public MutableRate newRate(String name) {
220 return newRate(name, name, false);
221 }
222
223 /**
224 * Create a mutable rate metric
225 * @param name of the metric
226 * @param description of the metric
227 * @return a new mutable rate metric object
228 */
229 public MutableRate newRate(String name, String description) {
230 return newRate(name, description, false);
231 }
232
233 /**
234 * Create a mutable rate metric (for throughput measurement)
235 * @param name of the metric
236 * @param desc description
237 * @param extended produce extended stat (stdev/min/max etc.) if true
238 * @return a new mutable rate metric object
239 */
240 public MutableRate newRate(String name, String desc, boolean extended) {
241 return newRate(name, desc, extended, true);
242 }
243
244 @InterfaceAudience.Private
245 public synchronized MutableRate newRate(String name, String desc,
246 boolean extended, boolean returnExisting) {
247 if (returnExisting) {
248 MutableMetric rate = metricsMap.get(name);
249 if (rate != null) {
250 if (rate instanceof MutableRate) return (MutableRate) rate;
251 throw new MetricsException("Unexpected metrics type "+ rate.getClass()
252 +" for "+ name);
253 }
254 }
255 checkMetricName(name);
256 MutableRate ret = new MutableRate(name, desc, extended);
257 metricsMap.put(name, ret);
258 return ret;
259 }
260
261 synchronized void add(String name, MutableMetric metric) {
262 checkMetricName(name);
263 metricsMap.put(name, metric);
264 }
265
266 /**
267 * Add sample to a stat metric by name.
268 * @param name of the metric
269 * @param value of the snapshot to add
270 */
271 public synchronized void add(String name, long value) {
272 MutableMetric m = metricsMap.get(name);
273
274 if (m != null) {
275 if (m instanceof MutableStat) {
276 ((MutableStat) m).add(value);
277 }
278 else {
279 throw new MetricsException("Unsupported add(value) for metric "+ name);
280 }
281 }
282 else {
283 metricsMap.put(name, newRate(name)); // default is a rate metric
284 add(name, value);
285 }
286 }
287
288 /**
289 * Set the metrics context tag
290 * @param name of the context
291 * @return the registry itself as a convenience
292 */
293 public MetricsRegistry setContext(String name) {
294 return tag(MsInfo.Context, name, true);
295 }
296
297 /**
298 * Add a tag to the metrics
299 * @param name of the tag
300 * @param description of the tag
301 * @param value of the tag
302 * @return the registry (for keep adding tags)
303 */
304 public MetricsRegistry tag(String name, String description, String value) {
305 return tag(name, description, value, false);
306 }
307
308 /**
309 * Add a tag to the metrics
310 * @param name of the tag
311 * @param description of the tag
312 * @param value of the tag
313 * @param override existing tag if true
314 * @return the registry (for keep adding tags)
315 */
316 public MetricsRegistry tag(String name, String description, String value,
317 boolean override) {
318 return tag(Interns.info(name, description), value, override);
319 }
320
321 /**
322 * Add a tag to the metrics
323 * @param info metadata of the tag
324 * @param value of the tag
325 * @param override existing tag if true
326 * @return the registry (for keep adding tags etc.)
327 */
328 public synchronized
329 MetricsRegistry tag(MetricsInfo info, String value, boolean override) {
330 if (!override) checkTagName(info.name());
331 tagsMap.put(info.name(), Interns.tag(info, value));
332 return this;
333 }
334
335 public MetricsRegistry tag(MetricsInfo info, String value) {
336 return tag(info, value, false);
337 }
338
339 Collection<MetricsTag> tags() {
340 return tagsMap.values();
341 }
342
343 Collection<MutableMetric> metrics() {
344 return metricsMap.values();
345 }
346
347 private void checkMetricName(String name) {
348 if (metricsMap.containsKey(name)) {
349 throw new MetricsException("Metric name "+ name +" already exists!");
350 }
351 }
352
353 private void checkTagName(String name) {
354 if (tagsMap.containsKey(name)) {
355 throw new MetricsException("Tag "+ name +" already exists!");
356 }
357 }
358
359 /**
360 * Sample all the mutable metrics and put the snapshot in the builder
361 * @param builder to contain the metrics snapshot
362 * @param all get all the metrics even if the values are not changed.
363 */
364 public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) {
365 for (MetricsTag tag : tags()) {
366 builder.add(tag);
367 }
368 for (MutableMetric metric : metrics()) {
369 metric.snapshot(builder, all);
370 }
371 }
372
373 @Override public String toString() {
374 return Objects.toStringHelper(this)
375 .add("info", metricsInfo).add("tags", tags()).add("metrics", metrics())
376 .toString();
377 }
378 }