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 019package org.apache.hadoop.metrics2.lib; 020 021import java.util.Collection; 022import java.util.Map; 023 024import com.google.common.collect.Maps; 025import com.google.common.base.Objects; 026 027import org.apache.hadoop.classification.InterfaceAudience; 028import org.apache.hadoop.classification.InterfaceStability; 029import org.apache.hadoop.metrics2.MetricsInfo; 030import org.apache.hadoop.metrics2.MetricsException; 031import org.apache.hadoop.metrics2.MetricsRecordBuilder; 032import org.apache.hadoop.metrics2.MetricsTag; 033import 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 041public 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 double gauge 185 * @param name of the metric 186 * @param desc metric description 187 * @param val initial value 188 * @return a new gauge object 189 */ 190 public MutableGaugeDouble newGauge(String name, String desc, double val) { 191 return newGauge(Interns.info(name, desc), val); 192 } 193 194 /** 195 * Create a mutable double gauge 196 * @param info metadata of the metric 197 * @param val initial value 198 * @return a new gauge object 199 */ 200 public synchronized MutableGaugeDouble newGauge(MetricsInfo info, double val) { 201 checkMetricName(info.name()); 202 MutableGaugeDouble ret = new MutableGaugeDouble(info, val); 203 metricsMap.put(info.name(), ret); 204 return ret; 205 } 206 207 /** 208 * Create a mutable metric that estimates quantiles of a stream of values 209 * @param name of the metric 210 * @param desc metric description 211 * @param sampleName of the metric (e.g., "Ops") 212 * @param valueName of the metric (e.g., "Time" or "Latency") 213 * @param interval rollover interval of estimator in seconds 214 * @return a new quantile estimator object 215 */ 216 public synchronized MutableQuantiles newQuantiles(String name, String desc, 217 String sampleName, String valueName, int interval) { 218 checkMetricName(name); 219 MutableQuantiles ret = 220 new MutableQuantiles(name, desc, sampleName, valueName, interval); 221 metricsMap.put(name, ret); 222 return ret; 223 } 224 225 /** 226 * Create a mutable metric with stats 227 * @param name of the metric 228 * @param desc metric description 229 * @param sampleName of the metric (e.g., "Ops") 230 * @param valueName of the metric (e.g., "Time" or "Latency") 231 * @param extended produce extended stat (stdev, min/max etc.) if true. 232 * @return a new mutable stat metric object 233 */ 234 public synchronized MutableStat newStat(String name, String desc, 235 String sampleName, String valueName, boolean extended) { 236 checkMetricName(name); 237 MutableStat ret = 238 new MutableStat(name, desc, sampleName, valueName, extended); 239 metricsMap.put(name, ret); 240 return ret; 241 } 242 243 /** 244 * Create a mutable metric with stats 245 * @param name of the metric 246 * @param desc metric description 247 * @param sampleName of the metric (e.g., "Ops") 248 * @param valueName of the metric (e.g., "Time" or "Latency") 249 * @return a new mutable metric object 250 */ 251 public MutableStat newStat(String name, String desc, 252 String sampleName, String valueName) { 253 return newStat(name, desc, sampleName, valueName, false); 254 } 255 256 /** 257 * Create a mutable rate metric 258 * @param name of the metric 259 * @return a new mutable metric object 260 */ 261 public MutableRate newRate(String name) { 262 return newRate(name, name, false); 263 } 264 265 /** 266 * Create a mutable rate metric 267 * @param name of the metric 268 * @param description of the metric 269 * @return a new mutable rate metric object 270 */ 271 public MutableRate newRate(String name, String description) { 272 return newRate(name, description, false); 273 } 274 275 /** 276 * Create a mutable rate metric (for throughput measurement) 277 * @param name of the metric 278 * @param desc description 279 * @param extended produce extended stat (stdev/min/max etc.) if true 280 * @return a new mutable rate metric object 281 */ 282 public MutableRate newRate(String name, String desc, boolean extended) { 283 return newRate(name, desc, extended, true); 284 } 285 286 @InterfaceAudience.Private 287 public synchronized MutableRate newRate(String name, String desc, 288 boolean extended, boolean returnExisting) { 289 if (returnExisting) { 290 MutableMetric rate = metricsMap.get(name); 291 if (rate != null) { 292 if (rate instanceof MutableRate) return (MutableRate) rate; 293 throw new MetricsException("Unexpected metrics type "+ rate.getClass() 294 +" for "+ name); 295 } 296 } 297 checkMetricName(name); 298 MutableRate ret = new MutableRate(name, desc, extended); 299 metricsMap.put(name, ret); 300 return ret; 301 } 302 303 synchronized void add(String name, MutableMetric metric) { 304 checkMetricName(name); 305 metricsMap.put(name, metric); 306 } 307 308 /** 309 * Add sample to a stat metric by name. 310 * @param name of the metric 311 * @param value of the snapshot to add 312 */ 313 public synchronized void add(String name, long value) { 314 MutableMetric m = metricsMap.get(name); 315 316 if (m != null) { 317 if (m instanceof MutableStat) { 318 ((MutableStat) m).add(value); 319 } 320 else { 321 throw new MetricsException("Unsupported add(value) for metric "+ name); 322 } 323 } 324 else { 325 metricsMap.put(name, newRate(name)); // default is a rate metric 326 add(name, value); 327 } 328 } 329 330 /** 331 * Set the metrics context tag 332 * @param name of the context 333 * @return the registry itself as a convenience 334 */ 335 public MetricsRegistry setContext(String name) { 336 return tag(MsInfo.Context, name, true); 337 } 338 339 /** 340 * Add a tag to the metrics 341 * @param name of the tag 342 * @param description of the tag 343 * @param value of the tag 344 * @return the registry (for keep adding tags) 345 */ 346 public MetricsRegistry tag(String name, String description, String value) { 347 return tag(name, description, value, false); 348 } 349 350 /** 351 * Add a tag to the metrics 352 * @param name of the tag 353 * @param description of the tag 354 * @param value of the tag 355 * @param override existing tag if true 356 * @return the registry (for keep adding tags) 357 */ 358 public MetricsRegistry tag(String name, String description, String value, 359 boolean override) { 360 return tag(Interns.info(name, description), value, override); 361 } 362 363 /** 364 * Add a tag to the metrics 365 * @param info metadata of the tag 366 * @param value of the tag 367 * @param override existing tag if true 368 * @return the registry (for keep adding tags etc.) 369 */ 370 public synchronized 371 MetricsRegistry tag(MetricsInfo info, String value, boolean override) { 372 if (!override) checkTagName(info.name()); 373 tagsMap.put(info.name(), Interns.tag(info, value)); 374 return this; 375 } 376 377 public MetricsRegistry tag(MetricsInfo info, String value) { 378 return tag(info, value, false); 379 } 380 381 Collection<MetricsTag> tags() { 382 return tagsMap.values(); 383 } 384 385 Collection<MutableMetric> metrics() { 386 return metricsMap.values(); 387 } 388 389 private void checkMetricName(String name) { 390 // Check for invalid characters in metric name 391 boolean foundWhitespace = false; 392 for (int i = 0; i < name.length(); i++) { 393 char c = name.charAt(i); 394 if (Character.isWhitespace(c)) { 395 foundWhitespace = true; 396 break; 397 } 398 } 399 if (foundWhitespace) { 400 throw new MetricsException("Metric name '"+ name + 401 "' contains illegal whitespace character"); 402 } 403 // Check if name has already been registered 404 if (metricsMap.containsKey(name)) { 405 throw new MetricsException("Metric name "+ name +" already exists!"); 406 } 407 } 408 409 private void checkTagName(String name) { 410 if (tagsMap.containsKey(name)) { 411 throw new MetricsException("Tag "+ name +" already exists!"); 412 } 413 } 414 415 /** 416 * Sample all the mutable metrics and put the snapshot in the builder 417 * @param builder to contain the metrics snapshot 418 * @param all get all the metrics even if the values are not changed. 419 */ 420 public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) { 421 for (MetricsTag tag : tags()) { 422 builder.add(tag); 423 } 424 for (MutableMetric metric : metrics()) { 425 metric.snapshot(builder, all); 426 } 427 } 428 429 @Override public String toString() { 430 return Objects.toStringHelper(this) 431 .add("info", metricsInfo).add("tags", tags()).add("metrics", metrics()) 432 .toString(); 433 } 434}