/metrics-core/src/main/java/com/yammer/metrics/core/MetricsRegistry.java

https://github.com/ntolia/metrics · Java · 511 lines · 217 code · 40 blank · 254 comment · 19 complexity · 488431674de2215d4edbf8efc349e2a0 MD5 · raw file

  1. package com.yammer.metrics.core;
  2. import com.yammer.metrics.core.Histogram.SampleType;
  3. import java.util.*;
  4. import java.util.concurrent.*;
  5. /**
  6. * A registry of metric instances.
  7. */
  8. public class MetricsRegistry {
  9. private static final int EXPECTED_METRIC_COUNT = 1024;
  10. private final Clock clock;
  11. private final ConcurrentMap<MetricName, Metric> metrics;
  12. private final List<MetricsRegistryListener> listeners;
  13. private final String name;
  14. /**
  15. * Creates a new {@link MetricsRegistry}.
  16. */
  17. public MetricsRegistry() {
  18. this(Clock.defaultClock());
  19. }
  20. /**
  21. * Creates a new {@link MetricsRegistry} with the given name.
  22. *
  23. * @param name the name of the registry
  24. */
  25. public MetricsRegistry(String name) {
  26. this(name, Clock.defaultClock());
  27. }
  28. /**
  29. * Creates a new {@link MetricsRegistry} with the given {@link Clock} instance.
  30. *
  31. * @param clock a {@link Clock} instance
  32. */
  33. public MetricsRegistry(Clock clock) {
  34. this(null, clock);
  35. }
  36. /**
  37. * Creates a new {@link MetricsRegistry} with the given name and {@link Clock} instance.
  38. *
  39. * @param name the name of the registry
  40. * @param clock a {@link Clock} instance
  41. */
  42. public MetricsRegistry(String name, Clock clock) {
  43. this.name = name;
  44. this.clock = clock;
  45. this.metrics = newMetricsMap();
  46. this.listeners = new CopyOnWriteArrayList<MetricsRegistryListener>();
  47. }
  48. /**
  49. * Given a new {@link Gauge}, registers it under the given class and name.
  50. *
  51. * @param klass the class which owns the metric
  52. * @param name the name of the metric
  53. * @param metric the metric
  54. * @param <T> the type of the value returned by the metric
  55. * @return {@code metric}
  56. */
  57. public <T> Gauge<T> newGauge(Class<?> klass,
  58. String name,
  59. Gauge<T> metric) {
  60. return newGauge(klass, name, null, metric);
  61. }
  62. /**
  63. * Given a new {@link Gauge}, registers it under the given class and name.
  64. *
  65. * @param klass the class which owns the metric
  66. * @param name the name of the metric
  67. * @param scope the scope of the metric
  68. * @param metric the metric
  69. * @param <T> the type of the value returned by the metric
  70. * @return {@code metric}
  71. */
  72. public <T> Gauge<T> newGauge(Class<?> klass,
  73. String name,
  74. String scope,
  75. Gauge<T> metric) {
  76. return newGauge(createName(klass, name, scope), metric);
  77. }
  78. /**
  79. * Given a new {@link Gauge}, registers it under the given metric name.
  80. *
  81. * @param metricName the name of the metric
  82. * @param metric the metric
  83. * @param <T> the type of the value returned by the metric
  84. * @return {@code metric}
  85. */
  86. public <T> Gauge<T> newGauge(MetricName metricName,
  87. Gauge<T> metric) {
  88. return getOrAdd(metricName, metric);
  89. }
  90. /**
  91. * Creates a new {@link Counter} and registers it under the given class and name.
  92. *
  93. * @param klass the class which owns the metric
  94. * @param name the name of the metric
  95. * @return a new {@link Counter}
  96. */
  97. public Counter newCounter(Class<?> klass,
  98. String name) {
  99. return newCounter(klass, name, null);
  100. }
  101. /**
  102. * Creates a new {@link Counter} and registers it under the given class and name.
  103. *
  104. * @param klass the class which owns the metric
  105. * @param name the name of the metric
  106. * @param scope the scope of the metric
  107. * @return a new {@link Counter}
  108. */
  109. public Counter newCounter(Class<?> klass,
  110. String name,
  111. String scope) {
  112. return newCounter(createName(klass, name, scope));
  113. }
  114. /**
  115. * Creates a new {@link Counter} and registers it under the given metric name.
  116. *
  117. * @param metricName the name of the metric
  118. * @return a new {@link Counter}
  119. */
  120. public Counter newCounter(MetricName metricName) {
  121. return getOrAdd(metricName, new Counter());
  122. }
  123. /**
  124. * Creates a new {@link Histogram} and registers it under the given class and name.
  125. *
  126. * @param klass the class which owns the metric
  127. * @param name the name of the metric
  128. * @param biased whether or not the histogram should be biased
  129. * @return a new {@link Histogram}
  130. */
  131. public Histogram newHistogram(Class<?> klass,
  132. String name,
  133. boolean biased) {
  134. return newHistogram(klass, name, null, biased);
  135. }
  136. /**
  137. * Creates a new {@link Histogram} and registers it under the given class, name, and scope.
  138. *
  139. * @param klass the class which owns the metric
  140. * @param name the name of the metric
  141. * @param scope the scope of the metric
  142. * @param biased whether or not the histogram should be biased
  143. * @return a new {@link Histogram}
  144. */
  145. public Histogram newHistogram(Class<?> klass,
  146. String name,
  147. String scope,
  148. boolean biased) {
  149. return newHistogram(createName(klass, name, scope), biased);
  150. }
  151. /**
  152. * Creates a new non-biased {@link Histogram} and registers it under the given class and name.
  153. *
  154. * @param klass the class which owns the metric
  155. * @param name the name of the metric
  156. * @return a new {@link Histogram}
  157. */
  158. public Histogram newHistogram(Class<?> klass,
  159. String name) {
  160. return newHistogram(klass, name, false);
  161. }
  162. /**
  163. * Creates a new non-biased {@link Histogram} and registers it under the given class, name, and
  164. * scope.
  165. *
  166. * @param klass the class which owns the metric
  167. * @param name the name of the metric
  168. * @param scope the scope of the metric
  169. * @return a new {@link Histogram}
  170. */
  171. public Histogram newHistogram(Class<?> klass,
  172. String name,
  173. String scope) {
  174. return newHistogram(klass, name, scope, false);
  175. }
  176. /**
  177. * Creates a new {@link Histogram} and registers it under the given metric name.
  178. *
  179. * @param metricName the name of the metric
  180. * @param biased whether or not the histogram should be biased
  181. * @return a new {@link Histogram}
  182. */
  183. public Histogram newHistogram(MetricName metricName,
  184. boolean biased) {
  185. return getOrAdd(metricName,
  186. new Histogram(biased ? SampleType.BIASED : SampleType.UNIFORM));
  187. }
  188. /**
  189. * Creates a new {@link Meter} and registers it under the given class and name.
  190. *
  191. * @param klass the class which owns the metric
  192. * @param name the name of the metric
  193. * @param eventType the plural name of the type of events the meter is measuring (e.g., {@code
  194. * "requests"})
  195. * @param unit the rate unit of the new meter
  196. * @return a new {@link Meter}
  197. */
  198. public Meter newMeter(Class<?> klass,
  199. String name,
  200. String eventType,
  201. TimeUnit unit) {
  202. return newMeter(klass, name, null, eventType, unit);
  203. }
  204. /**
  205. * Creates a new {@link Meter} and registers it under the given class, name, and scope.
  206. *
  207. * @param klass the class which owns the metric
  208. * @param name the name of the metric
  209. * @param scope the scope of the metric
  210. * @param eventType the plural name of the type of events the meter is measuring (e.g., {@code
  211. * "requests"})
  212. * @param unit the rate unit of the new meter
  213. * @return a new {@link Meter}
  214. */
  215. public Meter newMeter(Class<?> klass,
  216. String name,
  217. String scope,
  218. String eventType,
  219. TimeUnit unit) {
  220. return newMeter(createName(klass, name, scope), eventType, unit);
  221. }
  222. /**
  223. * Creates a new {@link Meter} and registers it under the given metric name.
  224. *
  225. * @param metricName the name of the metric
  226. * @param eventType the plural name of the type of events the meter is measuring (e.g., {@code
  227. * "requests"})
  228. * @param unit the rate unit of the new meter
  229. * @return a new {@link Meter}
  230. */
  231. public Meter newMeter(MetricName metricName,
  232. String eventType,
  233. TimeUnit unit) {
  234. final Metric existingMetric = metrics.get(metricName);
  235. if (existingMetric != null) {
  236. return (Meter) existingMetric;
  237. }
  238. return getOrAdd(metricName, new Meter(eventType, unit, clock));
  239. }
  240. /**
  241. * Creates a new {@link Timer} and registers it under the given class and name, measuring
  242. * elapsed time in milliseconds and invocations per second.
  243. *
  244. * @param klass the class which owns the metric
  245. * @param name the name of the metric
  246. * @return a new {@link Timer}
  247. */
  248. public Timer newTimer(Class<?> klass,
  249. String name) {
  250. return newTimer(klass, name, null, TimeUnit.MILLISECONDS, TimeUnit.SECONDS);
  251. }
  252. /**
  253. * Creates a new {@link Timer} and registers it under the given class and name.
  254. *
  255. * @param klass the class which owns the metric
  256. * @param name the name of the metric
  257. * @param durationUnit the duration scale unit of the new timer
  258. * @param rateUnit the rate scale unit of the new timer
  259. * @return a new {@link Timer}
  260. */
  261. public Timer newTimer(Class<?> klass,
  262. String name,
  263. TimeUnit durationUnit,
  264. TimeUnit rateUnit) {
  265. return newTimer(klass, name, null, durationUnit, rateUnit);
  266. }
  267. /**
  268. * Creates a new {@link Timer} and registers it under the given class, name, and scope,
  269. * measuring elapsed time in milliseconds and invocations per second.
  270. *
  271. * @param klass the class which owns the metric
  272. * @param name the name of the metric
  273. * @param scope the scope of the metric
  274. * @return a new {@link Timer}
  275. */
  276. public Timer newTimer(Class<?> klass,
  277. String name,
  278. String scope) {
  279. return newTimer(klass, name, scope, TimeUnit.MILLISECONDS, TimeUnit.SECONDS);
  280. }
  281. /**
  282. * Creates a new {@link Timer} and registers it under the given class, name, and scope.
  283. *
  284. * @param klass the class which owns the metric
  285. * @param name the name of the metric
  286. * @param scope the scope of the metric
  287. * @param durationUnit the duration scale unit of the new timer
  288. * @param rateUnit the rate scale unit of the new timer
  289. * @return a new {@link Timer}
  290. */
  291. public Timer newTimer(Class<?> klass,
  292. String name,
  293. String scope,
  294. TimeUnit durationUnit,
  295. TimeUnit rateUnit) {
  296. return newTimer(createName(klass, name, scope), durationUnit, rateUnit);
  297. }
  298. /**
  299. * Creates a new {@link Timer} and registers it under the given metric name.
  300. *
  301. * @param metricName the name of the metric
  302. * @param durationUnit the duration scale unit of the new timer
  303. * @param rateUnit the rate scale unit of the new timer
  304. * @return a new {@link Timer}
  305. */
  306. public Timer newTimer(MetricName metricName,
  307. TimeUnit durationUnit,
  308. TimeUnit rateUnit) {
  309. final Metric existingMetric = metrics.get(metricName);
  310. if (existingMetric != null) {
  311. return (Timer) existingMetric;
  312. }
  313. return getOrAdd(metricName,
  314. new Timer(durationUnit, rateUnit, clock));
  315. }
  316. /**
  317. * Returns an unmodifiable map of all metrics and their names.
  318. *
  319. * @return an unmodifiable map of all metrics and their names
  320. */
  321. public Map<MetricName, Metric> getAllMetrics() {
  322. return Collections.unmodifiableMap(metrics);
  323. }
  324. /**
  325. * Returns a grouped and sorted map of all registered metrics.
  326. *
  327. * @return all registered metrics, grouped by name and sorted
  328. */
  329. public SortedMap<String, SortedMap<MetricName, Metric>> getGroupedMetrics() {
  330. return getGroupedMetrics(MetricPredicate.ALL);
  331. }
  332. /**
  333. * Returns a grouped and sorted map of all registered metrics which match then given {@link
  334. * MetricPredicate}.
  335. *
  336. * @param predicate a predicate which metrics have to match to be in the results
  337. * @return all registered metrics which match {@code predicate}, sorted by name
  338. */
  339. public SortedMap<String, SortedMap<MetricName, Metric>> getGroupedMetrics(MetricPredicate predicate) {
  340. final SortedMap<String, SortedMap<MetricName, Metric>> groups =
  341. new TreeMap<String, SortedMap<MetricName, Metric>>();
  342. for (Map.Entry<MetricName, Metric> entry : metrics.entrySet()) {
  343. final String qualifiedTypeName = entry.getKey().getDomain() + "." + entry.getKey()
  344. .getType();
  345. if (predicate.matches(entry.getKey(), entry.getValue())) {
  346. final String scopedName;
  347. if (entry.getKey().hasScope()) {
  348. scopedName = qualifiedTypeName + "." + entry.getKey().getScope();
  349. } else {
  350. scopedName = qualifiedTypeName;
  351. }
  352. SortedMap<MetricName, Metric> group = groups.get(scopedName);
  353. if (group == null) {
  354. group = new TreeMap<MetricName, Metric>();
  355. groups.put(scopedName, group);
  356. }
  357. group.put(entry.getKey(), entry.getValue());
  358. }
  359. }
  360. return Collections.unmodifiableSortedMap(groups);
  361. }
  362. /**
  363. * Removes the metric for the given class with the given name.
  364. *
  365. * @param klass the klass the metric is associated with
  366. * @param name the name of the metric
  367. */
  368. public void removeMetric(Class<?> klass,
  369. String name) {
  370. removeMetric(klass, name, null);
  371. }
  372. /**
  373. * Removes the metric for the given class with the given name and scope.
  374. *
  375. * @param klass the klass the metric is associated with
  376. * @param name the name of the metric
  377. * @param scope the scope of the metric
  378. */
  379. public void removeMetric(Class<?> klass,
  380. String name,
  381. String scope) {
  382. removeMetric(createName(klass, name, scope));
  383. }
  384. /**
  385. * Removes the metric with the given name.
  386. *
  387. * @param name the name of the metric
  388. */
  389. public void removeMetric(MetricName name) {
  390. final Metric metric = metrics.remove(name);
  391. if (metric != null) {
  392. notifyMetricRemoved(name);
  393. }
  394. }
  395. /**
  396. * Adds a {@link MetricsRegistryListener} to a collection of listeners that will be notified on
  397. * metric creation. Listeners will be notified in the order in which they are added.
  398. * <p/>
  399. * <b>N.B.:</b> The listener will be notified of all existing metrics when it first registers.
  400. *
  401. * @param listener the listener that will be notified
  402. */
  403. public void addListener(MetricsRegistryListener listener) {
  404. listeners.add(listener);
  405. for (Map.Entry<MetricName, Metric> entry : metrics.entrySet()) {
  406. listener.onMetricAdded(entry.getKey(), entry.getValue());
  407. }
  408. }
  409. /**
  410. * Removes a {@link MetricsRegistryListener} from this registry's collection of listeners.
  411. *
  412. * @param listener the listener that will be removed
  413. */
  414. public void removeListener(MetricsRegistryListener listener) {
  415. listeners.remove(listener);
  416. }
  417. /**
  418. * Override to customize how {@link MetricName}s are created.
  419. *
  420. * @param klass the class which owns the metric
  421. * @param name the name of the metric
  422. * @param scope the metric's scope
  423. * @return the metric's full name
  424. */
  425. protected MetricName createName(Class<?> klass, String name, String scope) {
  426. return new MetricName(klass, name, scope);
  427. }
  428. /**
  429. * Returns a new {@link ConcurrentMap} implementation. Subclass this to do weird things with
  430. * your own {@link MetricsRegistry} implementation.
  431. *
  432. * @return a new {@link ConcurrentMap}
  433. */
  434. protected ConcurrentMap<MetricName, Metric> newMetricsMap() {
  435. return new ConcurrentHashMap<MetricName, Metric>(EXPECTED_METRIC_COUNT);
  436. }
  437. /**
  438. * Gets any existing metric with the given name or, if none exists, adds the given metric.
  439. *
  440. * @param name the metric's name
  441. * @param metric the new metric
  442. * @param <T> the type of the metric
  443. * @return either the existing metric or {@code metric}
  444. */
  445. @SuppressWarnings("unchecked")
  446. protected final <T extends Metric> T getOrAdd(MetricName name, T metric) {
  447. final Metric existingMetric = metrics.get(name);
  448. if (existingMetric == null) {
  449. final Metric justAddedMetric = metrics.putIfAbsent(name, metric);
  450. if (justAddedMetric == null) {
  451. notifyMetricAdded(name, metric);
  452. return metric;
  453. }
  454. return (T) justAddedMetric;
  455. }
  456. return (T) existingMetric;
  457. }
  458. private void notifyMetricRemoved(MetricName name) {
  459. for (MetricsRegistryListener listener : listeners) {
  460. listener.onMetricRemoved(name);
  461. }
  462. }
  463. private void notifyMetricAdded(MetricName name, Metric metric) {
  464. for (MetricsRegistryListener listener : listeners) {
  465. listener.onMetricAdded(name, metric);
  466. }
  467. }
  468. public String getName() {
  469. return name;
  470. }
  471. }