feat(gateway): add observability logging for vision cache hits/misses

Add debug logging to trace cacheKey + messageId + content length on
every vision cache HIT and MISS, so we can detect if the vision model
returns duplicate analysis for different images (provider issue vs
cache collision). Includes the phash on cache miss (new analysis cached).

Follow-up to 9f7ce7d which fixed makeImageCacheKey to hash full data
URL instead of just first 128 chars (root cause of all images sharing
the same cached 'konten judi' verdict due to hash collision).
This commit is contained in:
asepharyana
2026-08-12 19:22:56 +07:00
parent 9f7ce7dbd5
commit 3b221823e7
@@ -163,7 +163,10 @@ export const analyzeSingleMediaImage = async (
const cached = await getCachedMediaAnalysis(cacheKey);
if (cached && !isNoImageSeenText(cached)) {
visionLruCache.set(cacheKey, cached);
log.debug({ cacheKey }, "Media analysis cache HIT (DB → LRU)");
log.debug(
{ cacheKey, messageId, cachedLen: cached.length },
"Media analysis cache HIT (DB → LRU)",
);
return `[Media analysis for message ${messageId}] ${image.sourceLabel}: ${cached}`;
}
if (cached) {
@@ -246,6 +249,13 @@ export const analyzeSingleMediaImage = async (
try {
const content = await llmVision(promptText, image.image_url);
if (content && !isNoImageSeenText(content)) {
// Defensive: log when a vision analysis is cached so we can trace
// if the SAME analysis text is being stored for DIFFERENT cache keys
// (which would indicate the vision model is returning duplicates).
log.debug(
{ cacheKey, phash, messageId, contentLen: content.length },
"Vision analysis cached (new entry)",
);
await upsertCachedMediaAnalysis(
cacheKey,
content,