diff --git a/surfsense_backend/app/observability/metrics.py b/surfsense_backend/app/observability/metrics.py index 4751278a4..61b380722 100644 --- a/surfsense_backend/app/observability/metrics.py +++ b/surfsense_backend/app/observability/metrics.py @@ -305,6 +305,22 @@ def _etl_cache_evictions(): ) +@lru_cache(maxsize=1) +def _index_cache_lookups(): + return _get_meter().create_counter( + "surfsense.index.cache.lookups", + description="Count of index (chunk+embedding) cache lookups by outcome (hit/miss).", + ) + + +@lru_cache(maxsize=1) +def _index_cache_evictions(): + return _get_meter().create_counter( + "surfsense.index.cache.evictions", + description="Count of index cache entries evicted, by phase.", + ) + + @lru_cache(maxsize=1) def _celery_heartbeat_refreshes(): return _get_meter().create_counter( @@ -708,6 +724,28 @@ def record_etl_cache_eviction(count: int, *, phase: str) -> None: _add(_etl_cache_evictions(), count, {"phase": phase}) +def record_index_cache_lookup( + *, embedding_model: str | None, chunker_kind: str | None, outcome: str +) -> None: + """Record an index-cache lookup. ``outcome`` is ``hit`` or ``miss``.""" + _add( + _index_cache_lookups(), + 1, + { + "embedding.model": embedding_model or "unknown", + "chunker.kind": chunker_kind or "unknown", + "outcome": outcome, + }, + ) + + +def record_index_cache_eviction(count: int, *, phase: str) -> None: + """Record evicted entries. ``phase`` is ``ttl`` or ``size``.""" + if count <= 0: + return + _add(_index_cache_evictions(), count, {"phase": phase}) + + def record_celery_heartbeat_refresh(*, heartbeat_type: str) -> None: _add(_celery_heartbeat_refreshes(), 1, {"heartbeat.type": heartbeat_type}) @@ -908,6 +946,8 @@ __all__ = [ "record_etl_cache_lookup", "record_etl_extract_duration", "record_etl_extract_outcome", + "record_index_cache_eviction", + "record_index_cache_lookup", "record_indexing_document_duration", "record_indexing_document_outcome", "record_interrupt",