/** * Enables the accumulation of {@link CacheStats} during the operation of the cache. Without this * {@link Cache#stats} will return zero for all statistics. Note that recording statistics * requires bookkeeping to be performed with each operation, and thus imposes a performance * penalty on cache operation. Any exception thrown by the supplied {@link StatsCounter} will be * suppressed and logged. * * @param statsCounterSupplier a supplier instance that returns a new {@link StatsCounter} * @return this {@code Caffeine} instance (for chaining) */ @NonNull public Caffeine<K, V> recordStats( @NonNull Supplier<? extends StatsCounter> statsCounterSupplier) { requireState(this.statsCounterSupplier == null, "Statistics recording was already set"); requireNonNull(statsCounterSupplier); this.statsCounterSupplier = () -> StatsCounter.guardedStatsCounter(statsCounterSupplier.get()); return this; }
@Test public void guarded() { StatsCounter counter = StatsCounter.guardedStatsCounter(new ConcurrentStatsCounter()); counter.recordHits(1); counter.recordMisses(1); counter.recordEviction(); counter.recordEviction(10); counter.recordLoadSuccess(1); counter.recordLoadFailure(1); CacheStats expected = new CacheStats(1, 1, 1, 1, 2, 2, 10); assertThat(counter.snapshot(), is(expected)); assertThat(counter.toString(), is(expected.toString())); assertThat(counter.snapshot().toString(), is(expected.toString())); }
@Test public void guarded_exception() { StatsCounter statsCounter = Mockito.mock(StatsCounter.class); when(statsCounter.snapshot()).thenThrow(new NullPointerException()); doThrow(NullPointerException.class).when(statsCounter).recordEviction(); doThrow(NullPointerException.class).when(statsCounter).recordHits(anyInt()); doThrow(NullPointerException.class).when(statsCounter).recordMisses(anyInt()); doThrow(NullPointerException.class).when(statsCounter).recordEviction(anyInt()); doThrow(NullPointerException.class).when(statsCounter).recordLoadSuccess(anyLong()); doThrow(NullPointerException.class).when(statsCounter).recordLoadFailure(anyLong()); StatsCounter guarded = StatsCounter.guardedStatsCounter(statsCounter); guarded.recordHits(1); guarded.recordMisses(1); guarded.recordEviction(); guarded.recordEviction(10); guarded.recordLoadSuccess(1); guarded.recordLoadFailure(1); assertThat(guarded.snapshot(), is(CacheStats.empty())); verify(statsCounter).recordHits(1); verify(statsCounter).recordMisses(1); verify(statsCounter).recordEviction(); verify(statsCounter).recordEviction(10); verify(statsCounter).recordLoadSuccess(1); verify(statsCounter).recordLoadFailure(1); } }
/** * Enables the accumulation of {@link CacheStats} during the operation of the cache. Without this * {@link Cache#stats} will return zero for all statistics. Note that recording statistics * requires bookkeeping to be performed with each operation, and thus imposes a performance * penalty on cache operation. Any exception thrown by the supplied {@link StatsCounter} will be * suppressed and logged. * * @param statsCounterSupplier a supplier instance that returns a new {@link StatsCounter} * @return this builder instance */ @Nonnull public Caffeine<K, V> recordStats( @Nonnull Supplier<? extends StatsCounter> statsCounterSupplier) { requireState(this.statsCounterSupplier == null, "Statistics recording was already set"); requireNonNull(statsCounterSupplier); this.statsCounterSupplier = () -> StatsCounter.guardedStatsCounter(statsCounterSupplier.get()); return this; }