/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.actuate.metrics.cache;

import java.util.Collection;
import java.util.Objects;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.binder.MeterBinder;

import org.springframework.boot.util.LambdaSafe;
import org.springframework.cache.Cache;
import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
import org.springframework.util.ClassUtils;

Register supported Cache to a MeterRegistry.
Author:Stephane Nicoll
Since:2.0.0
/** * Register supported {@link Cache} to a {@link MeterRegistry}. * * @author Stephane Nicoll * @since 2.0.0 */
public class CacheMetricsRegistrar { private final MeterRegistry registry; private final Collection<CacheMeterBinderProvider<?>> binderProviders;
Creates a new registrar.
Params:
  • registry – the MeterRegistry to use
  • binderProviders – the CacheMeterBinderProvider instances that should be used to detect compatible caches
/** * Creates a new registrar. * @param registry the {@link MeterRegistry} to use * @param binderProviders the {@link CacheMeterBinderProvider} instances that should * be used to detect compatible caches */
public CacheMetricsRegistrar(MeterRegistry registry, Collection<CacheMeterBinderProvider<?>> binderProviders) { this.registry = registry; this.binderProviders = binderProviders; }
Attempt to bind the specified Cache to the registry. Return true if the cache is supported and was bound to the registry, false otherwise.
Params:
  • cache – the cache to handle
  • tags – the tags to associate with the metrics of that cache
Returns:true if the cache is supported and was registered
/** * Attempt to bind the specified {@link Cache} to the registry. Return {@code true} if * the cache is supported and was bound to the registry, {@code false} otherwise. * @param cache the cache to handle * @param tags the tags to associate with the metrics of that cache * @return {@code true} if the {@code cache} is supported and was registered */
public boolean bindCacheToRegistry(Cache cache, Tag... tags) { MeterBinder meterBinder = getMeterBinder(unwrapIfNecessary(cache), Tags.of(tags)); if (meterBinder != null) { meterBinder.bindTo(this.registry); return true; } return false; } @SuppressWarnings({ "unchecked" }) private MeterBinder getMeterBinder(Cache cache, Tags tags) { Tags cacheTags = tags.and(getAdditionalTags(cache)); return LambdaSafe.callbacks(CacheMeterBinderProvider.class, this.binderProviders, cache) .withLogger(CacheMetricsRegistrar.class) .invokeAnd((binderProvider) -> binderProvider.getMeterBinder(cache, cacheTags)).filter(Objects::nonNull) .findFirst().orElse(null); }
Return additional tags to be associated with the given Cache.
Params:
  • cache – the cache
Returns:a list of additional tags to associate to that cache.
/** * Return additional {@link Tag tags} to be associated with the given {@link Cache}. * @param cache the cache * @return a list of additional tags to associate to that {@code cache}. */
protected Iterable<Tag> getAdditionalTags(Cache cache) { return Tags.of("name", cache.getName()); } private Cache unwrapIfNecessary(Cache cache) { if (ClassUtils.isPresent("org.springframework.cache.transaction.TransactionAwareCacheDecorator", getClass().getClassLoader())) { return TransactionAwareCacheDecoratorHandler.unwrapIfNecessary(cache); } return cache; } private static class TransactionAwareCacheDecoratorHandler { private static Cache unwrapIfNecessary(Cache cache) { try { if (cache instanceof TransactionAwareCacheDecorator) { return ((TransactionAwareCacheDecorator) cache).getTargetCache(); } } catch (NoClassDefFoundError ex) { // Ignore } return cache; } } }