private static AtomicLong getGauge(String name, String... additionalTags) { String key = className + "." + name + "." + Joiner.on(",").join(additionalTags); return gauges.computeIfAbsent(key, pollTimer -> { Id id = registry.createId(name, getTags(additionalTags)); return PolledMeter.using(registry) .withId(id) .monitorValue(new AtomicLong(0)); }); }
@Override public void registerGauge(String id, Supplier<Number> supplier, String... tagNameValuePairs) { Id metricId = suffixBaseId(id).withTags(tagNameValuePairs); PolledMeter.remove(registry, metricId); PolledMeter.using(registry) .withId(metricId) .monitorValue(supplier, ignore -> supplier.get().doubleValue()); }
@Inject public CassMonitorMetrics(Registry registry) { cassStop = registry.gauge(Metrics.METRIC_PREFIX + "cass.stop"); cassStart = registry.gauge(Metrics.METRIC_PREFIX + "cass.start"); cassAutoStart = registry.gauge(Metrics.METRIC_PREFIX + "cass.auto.start"); getSeedsCnt = PolledMeter.using(registry) .withName(Metrics.METRIC_PREFIX + "cass.getSeedCnt") .monitorMonotonicCounter(new AtomicLong(0)); getTokenCnt = PolledMeter.using(registry) .withName(Metrics.METRIC_PREFIX + "cass.getTokenCnt") .monitorMonotonicCounter(new AtomicLong(0)); getReplacedIpCnt = PolledMeter.using(registry) .withName(Metrics.METRIC_PREFIX + "cass.getReplacedIpCnt") .monitorMonotonicCounter(new AtomicLong(0)); doubleRingCnt = PolledMeter.using(registry) .withName(Metrics.METRIC_PREFIX + "cass.doubleRingCnt") .monitorMonotonicCounter(new AtomicLong(0)); }
/** Create builder for a polled gauge based on the config. */ public static PolledMeter.Builder polledGauge(MonitorConfig config) { long delayMillis = Math.max(Pollers.getPollingIntervals().get(0) - 1000, 5000); Id id = createId(config); PolledMeter.remove(registry, id); return PolledMeter.using(registry) .withId(id) .withDelay(Duration.ofMillis(delayMillis)) .scheduleOn(gaugePool()); }
private static AtomicLong getGauge(String name, String... additionalTags) { String key = className + "." + name + "." + Joiner.on(",").join(additionalTags); return gauges.computeIfAbsent(key, pollTimer -> { Id id = registry.createId(name, getTags(additionalTags)); return PolledMeter.using(registry) .withId(id) .monitorValue(new AtomicLong(0)); }); }
/** * Tells the registry to regularly poll the value of a {@link java.lang.Number} and report * it as a gauge. See {@link #gauge(Id, Number)} for more information. * * @param id * Identifier for the metric being registered. * @param number * Thread-safe implementation of {@link Number} used to access the value. * @return * The number that was passed in so the registration can be done as part of an assignment * statement. * @deprecated * Use {@link PolledMeter} instead. This method has been deprecated to help * reduce confusion between active gauges that are explicitly updated by the * user and passive gauges that are polled in the background. Going forward * the registry methods will only be used for the core types directly updated * by the user. Other patterns such as {@link PolledMeter}s will be handled * separately. Scheduled to be removed in 2.0. */ @Deprecated default <T extends Number> T gauge(Id id, T number) { return PolledMeter.using(this).withId(id).monitorValue(number); }
/** * See {@link #gauge(Id, Object, ToDoubleFunction)} for more information. * * @param id * Identifier for the metric being registered. * @param obj * Object used to compute a value. * @param f * Function that is applied on the value for the number. * @return * The object that was passed in so the registration can be done as part of an assignment * statement. * @deprecated * Use {@link PolledMeter} instead. This method has been deprecated to help * reduce confusion between active gauges that are explicitly updated by the * user and passive gauges that are polled in the background. Going forward * the registry methods will only be used for the core types directly updated * by the user. Other patterns such as {@link PolledMeter}s will be handled * separately. Scheduled to be removed in 2.0. */ @Deprecated default <T> T gauge(Id id, T obj, ToDoubleFunction<T> f) { return PolledMeter.using(this).withId(id).monitorValue(obj, f); }
/** Create builder for a polled gauge based on the config. */ public static PolledMeter.Builder polledGauge(MonitorConfig config) { long delayMillis = Math.max(Pollers.getPollingIntervals().get(0) - 1000, 5000); Id id = createId(config); PolledMeter.remove(registry, id); return PolledMeter.using(registry) .withId(id) .withDelay(Duration.ofMillis(delayMillis)) .scheduleOn(gaugePool()); }
/** Create a new instance. */ Stats(Registry registry, String id) { this.registry = registry; activeCount = PolledMeter.using(registry) .withId(newId(registry, id, "activeThreads")) .monitorValue(new AtomicInteger()); taskExecutionTime = registry.timer(newId(registry, id, "taskExecutionTime")); taskExecutionDelay = registry.timer(newId(registry, id, "taskExecutionDelay")); skipped = registry.counter(newId(registry, id, "skipped")); uncaughtExceptionsId = newId(registry, id, "uncaughtExceptions"); }
/** Create a new instance. */ Stats(Registry registry, String id) { this.registry = registry; activeCount = PolledMeter.using(registry) .withId(newId(registry, id, "activeThreads")) .monitorValue(new AtomicInteger()); taskExecutionTime = registry.timer(newId(registry, id, "taskExecutionTime")); taskExecutionDelay = registry.timer(newId(registry, id, "taskExecutionDelay")); skipped = registry.counter(newId(registry, id, "skipped")); uncaughtExceptionsId = newId(registry, id, "uncaughtExceptions"); }
/** * Create a new IntervalCounter using the given registry and base id. */ IntervalCounter(Registry registry, Id id) { this.clock = registry.clock(); this.id = id; this.counter = registry.counter(id.withTag(Statistic.count)); this.lastUpdated = PolledMeter.using(registry) .withId(id) .withTag(Statistic.duration) .monitorValue(new AtomicLong(0L), Functions.age(clock)); }
/** * Create a new IntervalCounter using the given registry and base id. */ IntervalCounter(Registry registry, Id id) { this.clock = registry.clock(); this.id = id; this.counter = registry.counter(id.withTag(Statistic.count)); this.lastUpdated = PolledMeter.using(registry) .withId(id) .withTag(Statistic.duration) .monitorValue(new AtomicLong(0L), Functions.age(clock)); }
/** * Create a new instance. * * @param registry * Registry to use for collecting metrics. The clock from the registry will also be * used as the clock source for accessing the time. * @param id * Id for this instance of the scheduler. Used to distinguish between instances of * the scheduler for metrics and thread names. Threads will be named as * {@code spectator-$id-$i}. * @param poolSize * Number of threads to have in the pool. The threads will not be started until the * first task is scheduled. */ public Scheduler(Registry registry, String id, int poolSize) { this.clock = registry.clock(); PolledMeter.using(registry) .withId(newId(registry, id, "queueSize")) .monitorSize(queue); stats = new Stats(registry, id); this.factory = newThreadFactory(id); this.threads = new Thread[poolSize]; }
@Test public void expire() throws Exception { WeakReference<LongAdder> ref = new WeakReference<>( PolledMeter.using(registry).withId(id).monitorMonotonicCounter(new LongAdder())); while (ref.get() != null) { System.gc(); } Assertions.assertEquals(1, registry.state().size()); update(); Assertions.assertEquals(0, registry.state().size()); }
@Test public void uncaughtExceptionFromGaugeFunction() { Assertions.assertThrows(RuntimeException.class, () -> { Registry registry = new DefaultRegistry(); PolledMeter.using(registry) .withName("test") .monitorValue(new RuntimeException("failure"), value -> { throw value; }); PolledMeter.update(registry); }); } }
@Test public void removeGauge() throws Exception { LongAdder v = PolledMeter.using(registry).withId(id).monitorMonotonicCounter(new LongAdder()); Assertions.assertEquals(1, registry.state().size()); PolledMeter.remove(registry, id); Assertions.assertEquals(0, registry.state().size()); }
@Test public void usingAtomicLong() { AtomicLong count = new AtomicLong(); AtomicLong c = PolledMeter.using(registry).withId(id).monitorMonotonicCounter(count); Assertions.assertSame(count, c); Counter counter = registry.counter(id); update(); Assertions.assertEquals(0L, counter.count()); c.incrementAndGet(); update(); Assertions.assertEquals(1L, counter.count()); c.addAndGet(42); update(); Assertions.assertEquals(43L, counter.count()); }
@Test public void nonMonotonicUpdates() { AtomicLong count = new AtomicLong(); AtomicLong c = PolledMeter.using(registry).withId(id).monitorMonotonicCounter(count); Counter counter = registry.counter(id); update(); Assertions.assertEquals(0L, counter.count()); c.set(42L); update(); Assertions.assertEquals(42L, counter.count()); // Should not update the counter because it is lower, but must update // the previous recorded value c.set(21L); update(); Assertions.assertEquals(42L, counter.count()); // Make sure a subsequent increase is detected c.set(23L); update(); Assertions.assertEquals(44L, counter.count()); }
@Test public void usingLongAdder() { LongAdder count = new LongAdder(); LongAdder c = PolledMeter.using(registry).withId(id).monitorMonotonicCounter(count); Assertions.assertSame(count, c); Counter counter = registry.counter(id); update(); Assertions.assertEquals(0L, counter.count()); c.increment(); update(); Assertions.assertEquals(1L, counter.count()); c.add(42); update(); Assertions.assertEquals(43L, counter.count()); }