Punit Kulal
Punit Kulal

Reputation: 129

Unable to look at cache metrics(hit/miss/size) in spring boot?

I have implemented two cacheManagers. One using caffiene and one using redis. I have exposed them as beans and they are working as expected of them. There isn't any cache endpoint in the list available at /actuator/metrics path either.
I was able to only load /actuator/caches and /actuator/caches/{cacheName} endpoint. These endpoint only show the name and class of the cache being used. I am unable to see any metrics related to them. I am using springboot 2.1.3 and spring-boot-actuator.

 @Bean
    public CacheManager caffeine() {
        CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
        caffeineCacheManager.setCaffeine(caffeineCacheBuilder());
        return caffeineCacheManager;
    }

    private Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder().
                initialCapacity(initialCapacity).
                maximumSize(maxCapacity).
                expireAfterAccess(Duration.parse(ttl)).
                recordStats();
    }

Upvotes: 5

Views: 7698

Answers (2)

Huseyin Aydin
Huseyin Aydin

Reputation: 828

I would like to emphasize Punit Kulal's suggestion. If you are not configuring your caches explicitly, CacheMetricsRegistirar cannot register your caches to micrometer. You need to create caches statically and then consume them with @Cacheable(cacheNames = "yourCacheName"). In this example I'm using cache2k implementation, feel free to change it according to yours.

First make sure that your caching implementation's micrometer binder library is added as dependency:

<dependency>
    <groupId>org.cache2k</groupId>
    <artifactId>cache2k-micrometer</artifactId>
</dependency>

Explicitly create your caches:

@Configuration
public class CacheConfig {

  @Bean
  public CacheManager cacheManager() {
    SpringCache2kCacheManager manager = new SpringCache2kCacheManager();
    manager.addCache("yourCacheName",
                     cache2kBuilder -> cache2kBuilder.entryCapacity(10L).expireAfterWrite(12L, TimeUnit.HOURS));
    return manager;
  }
}

You can still consume your cache with @Caching annotation but this time it's not created on the fly:

@Service
public class CacheableService {

  @Cacheable(cacheNames = "yourCacheName")
  public StockDetailResponse getExchanges(String symbol, LocalDate date) {
    return "Cached";   
  }
}

As a side note you should be able to see cache related fields when you send GET request to http://localhost:8080/actuator/metrics

{
    "names": [
        "application.ready.time",
        "application.started.time",
        "cache.evictions",
        "cache.gets",
        "cache.puts",
        "cache.size",
    ]
}

Now you can access cache hit counts by following GET request:

curl 'http://localhost:8080/actuator/metrics/cache.gets'

Response:

{
    "name": "cache.gets",
    "description": "The number of times cache lookup methods have returned a cached (hit) or uncached (newly loaded or null) value (miss).",
    "measurements": [
        {
            "statistic": "COUNT",
            "value": 0.0
        }
    ],
    "availableTags": [
        {
            "tag": "valueType=",
            "values": [
                "Object"
            ]
        },
        {
            "tag": "result",
            "values": [
                "hit",
                "miss"
            ]
        },
        {
            "tag": "cache.manager",
            "values": [
                "cacheManager"
            ]
        },
        {
            "tag": "keyType=",
            "values": [
                "Object"
            ]
        },
        {
            "tag": "cache",
            "values": [
                "symbols"
            ]
        },
        {
            "tag": "cache2kCacheManager",
            "values": [
                "springDefault"
            ]
        },
        {
            "tag": "name",
            "values": [
                "yourCacheName"
            ]
        }
    ]
}

Upvotes: 1

Punit Kulal
Punit Kulal

Reputation: 129

Turned out @Cacheable makes the cache dynamically at runtime, thus if we want the annotated caches to have metrics, we have to set the cache names explicitly in the cacheManagerBean which inturn makes the cacheManager static.
Or create a custom registryBinder as stated in after upgrade to Spring Boot 2, how to expose cache metrics to prometheus? and call the register method only after the cache is created.

Upvotes: 4

Related Questions