Skip to content

Cache abstraction does not log hit / miss for synchronized access #25248

@elab

Description

@elab

General logging of hit / miss has been added in #16277.
For synchronized cache contexts (@Cacheable(sync=true)), no logging happens yet.
It's also not that straightforward, since in that case the mapping function will be passed directly to the Cache implementation (e.g. Caffeine) and Spring has no knowledge about if the mapper function has been called or if the returned value has been retrieved from the cache.

What we can do? I would propose to decorate the mapping function with an "invoked" flag (which will tell if the function has been invoked by the cache implementation) and with a logging for the "miss" case. The logging directly inside the function is necessary because we want to log misses before invocation of the underlying mapper function. The flag "invoked" is necessary to recognize the "hit" case (we can only definitely say that after the value has been returned from the cache implementation).

Here is the place in the code:

if (contexts.isSynchronized()) {
CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
Cache cache = context.getCaches().iterator().next();
try {
return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
}

The line return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker)))); could be changed to something like that:

boolean[] invoked = new boolean[1];
Object returnValue = wrapCacheValue(method, cache.get(key, () -> {
    invoked[0] = true; // cache miss; log "miss" *before* calling the underlying mapper function
    if (logger.isTraceEnabled()) {
        logger.trace("No cache entry for key '" + key + "' in cache " + cache.getName());
    }
    unwrapReturnValue(invokeOperation(invoker)));
});
if (!invoked[0]) { // cache hit; log "hit" after retrieving the value from the cache
    if (logger.isTraceEnabled()) {
        logger.trace("Cache entry for key '" + key + "' found in cache '" + cache.getName() + "'");
    }
}
return returnValue;

What do you think? Perhaps any easier solution possible?

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions