Spaces:
Sleeping
Sleeping
File size: 11,691 Bytes
2e818da | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | """Behavioural tests for the single operation boundary.
These assert on the actual emitted artefacts -- local-store rows, span
attributes, recorded histogram points, correlated log records -- not merely
that no exception was raised.
"""
from __future__ import annotations
import logging
import pytest
from app.observability import bootstrap
from app.observability.config import ObservabilityConfig
from app.observability.contracts import ExperimentIdentity, RetrievalOutcome
from app.observability.local_store import LocalObservationStore
from app.observability.logging import emit_correlated_log
from app.observability.operation import observe_operation, record_event
@pytest.fixture(autouse=True)
def _shutdown_after(tmp_path):
"""Ensure global observability state is torn down between tests."""
yield
bootstrap.shutdown_observability(timeout_seconds=2.0)
def _local_config(tmp_path) -> ObservabilityConfig:
return ObservabilityConfig(
enabled=True,
mode="local",
otlp_endpoint="http://127.0.0.1:4318",
signoz_ui_url="http://127.0.0.1:8080",
artifact_root=tmp_path,
)
# --- Brief Step 2 example ---------------------------------------------------
def test_local_mode_writes_the_same_completed_observation_used_by_span(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("retrieval.vector_search", store=store) as op:
op.set("raw_candidate_count", 12)
row = store.latest()
assert row["operation"] == "retrieval.vector_search"
assert row["duration_ms"] >= 0
assert row["attributes"]["raw_candidate_count"] == 12
# --- Store contents ---------------------------------------------------------
def test_default_status_is_success(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("rag.request", store=store):
pass
assert store.latest()["status"] == "success"
def test_subsystem_and_consumer_recorded(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("retrieval.vector_search", store=store, subsystem="chroma", consumer="chat"):
pass
row = store.latest()
assert row["subsystem"] == "chroma"
assert row["consumer"] == "chat"
def test_stage_durations_and_counts_recorded(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("rag.request", store=store) as op:
op.add_stage("embedding", 5.0)
op.add_count("candidates", 7)
row = store.latest()
assert row["stage_durations_ms"]["embedding"] == 5.0
assert row["counts"]["candidates"] == 7
def test_retrieval_outcome_recorded(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("retrieval.vector_search", store=store) as op:
op.set_retrieval(RetrievalOutcome.failure("ChromaError"))
row = store.latest()
assert row["retrieval"]["status"] == "error_fallback"
assert row["retrieval"]["retrieval_error"] is True
def test_experiment_identity_recorded(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("rag.request", store=store) as op:
op.set_experiment(ExperimentIdentity(experiment_id="exp1", pipeline_version="rag-naive-v1"))
row = store.latest()
assert row["experiment"]["experiment_id"] == "exp1"
assert row["experiment"]["pipeline_version"] == "rag-naive-v1"
def test_forbidden_attribute_is_redacted_in_store(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("rag.request", store=store) as op:
op.set("prompt", "the raw user prompt")
op.set("raw_candidate_count", 3)
row = store.latest()
assert row["attributes"]["prompt"] == "[redacted]"
assert row["attributes"]["raw_candidate_count"] == 3
# --- Exception handling -----------------------------------------------------
def test_exception_marks_error_status_and_reraises(tmp_path):
store = LocalObservationStore(tmp_path)
with pytest.raises(ValueError):
with observe_operation("rag.request", store=store):
raise ValueError("boom")
row = store.latest()
assert row["status"] == "error"
assert row["attributes"].get("error.type") == "ValueError"
def test_mark_error_sets_status_without_exception(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("retrieval.vector_search", store=store) as op:
op.mark_error("collection_missing")
row = store.latest()
assert row["status"] == "error"
assert row["attributes"].get("error.type") == "collection_missing"
def test_mark_terminal_overrides_status(tmp_path):
store = LocalObservationStore(tmp_path)
with observe_operation("retrieval.vector_search", store=store) as op:
op.mark_terminal("success_empty")
assert store.latest()["status"] == "success_empty"
# --- disabled mode ----------------------------------------------------------
def test_disabled_mode_is_a_no_op_but_runs_product_code(tmp_path):
bootstrap.initialize_observability(
config=ObservabilityConfig(
enabled=False,
mode="disabled",
otlp_endpoint="http://127.0.0.1:4318",
signoz_ui_url="http://127.0.0.1:8080",
artifact_root=tmp_path,
)
)
ran = False
with observe_operation("rag.request") as op:
op.set("raw_candidate_count", 1) # must not raise
ran = True
assert ran is True
# No global store in disabled mode -> nothing written.
assert bootstrap.get_state().local_store is None
# --- local mode global init: spans + metrics -------------------------------
def test_local_mode_creates_span_with_sanitized_attributes(tmp_path):
bootstrap.initialize_observability(config=_local_config(tmp_path))
with observe_operation("retrieval.vector_search") as op:
op.set("raw_candidate_count", 9)
spans = bootstrap.get_captured_spans()
assert len(spans) == 1
span = spans[0]
assert span.name == "retrieval.vector_search"
assert span.attributes["raw_candidate_count"] == 9
assert span.attributes["operation"] == "retrieval.vector_search"
def test_local_mode_records_duration_histogram(tmp_path):
bootstrap.initialize_observability(config=_local_config(tmp_path))
with observe_operation("retrieval.vector_search", consumer="chat"):
pass
points = bootstrap.collect_histogram_points("operation_duration_ms")
assert points, "expected at least one histogram data point"
dims = points[0].attributes
assert dims["operation"] == "retrieval.vector_search"
# consumer is a metric-safe dimension
assert dims.get("consumer") == "chat"
# raw operation IDs must never become metric dimensions
assert "trace_id" not in dims
def test_local_mode_global_store_written_without_explicit_store(tmp_path):
bootstrap.initialize_observability(config=_local_config(tmp_path))
with observe_operation("rag.request") as op:
op.set("raw_candidate_count", 4)
row = bootstrap.get_state().local_store.latest()
assert row["operation"] == "rag.request"
assert row["attributes"]["raw_candidate_count"] == 4
# --- correlated logging -----------------------------------------------------
def test_error_emits_correlated_log(tmp_path, caplog):
store = LocalObservationStore(tmp_path)
with caplog.at_level(logging.ERROR, logger="app.observability"):
with observe_operation("retrieval.vector_search", store=store, consumer="chat") as op:
op.mark_error("collection_missing")
records = [r for r in caplog.records if getattr(r, "otel_operation", None) == "retrieval.vector_search"]
assert records, "expected a correlated log record for the error"
rec = records[0]
assert rec.otel_status == "error"
assert rec.otel_error_type == "collection_missing"
assert rec.otel_consumer == "chat"
def test_success_does_not_emit_error_log(tmp_path, caplog):
store = LocalObservationStore(tmp_path)
with caplog.at_level(logging.ERROR, logger="app.observability"):
with observe_operation("rag.request", store=store):
pass
assert not [r for r in caplog.records if getattr(r, "otel_operation", None)]
# --- span-start failure must degrade, never propagate -----------------------
def test_span_start_failure_still_runs_product_body_and_records(tmp_path, monkeypatch):
"""A tracer that fails to start/enter a span must degrade to a no-span
operation -- the product body inside the `with` must still run untouched.
Regression guard: span setup used to sit outside the protective try-block.
"""
bootstrap.initialize_observability(config=_local_config(tmp_path))
tracer = bootstrap.get_state().tracer
def _boom(*_args, **_kwargs):
raise RuntimeError("tracer exploded on start_as_current_span")
monkeypatch.setattr(tracer, "start_as_current_span", _boom)
ran = False
result = None
with observe_operation("retrieval.vector_search") as op:
op.set("raw_candidate_count", 5) # must not raise despite no span
ran = True
result = "product-result"
assert ran is True
assert result == "product-result"
# No span was created, so no captured spans and no trace id ...
assert bootstrap.get_captured_spans() == []
# ... but the observation was still recorded with the product attribute.
row = bootstrap.get_state().local_store.latest()
assert row["operation"] == "retrieval.vector_search"
assert row["attributes"]["raw_candidate_count"] == 5
assert row["trace_id"] is None
# --- log export is scoped to the sanitized correlated-log path only ---------
def test_ordinary_app_logs_are_not_exported_only_sanitized_correlated_logs_are(tmp_path):
"""The OTel log handler must be scoped to ``app.observability`` so ordinary
``app.*`` logs (which routinely embed filesystem paths) never reach the log
pipeline -- only ``emit_correlated_log``'s path-stripped records do.
"""
bootstrap.initialize_observability(config=_local_config(tmp_path))
# Drop the bootstrap's own init log so we assert on a clean pipeline.
bootstrap.get_state().log_exporter.clear()
secret_path = "C:\\Users\\SystemSu\\.studybuddy\\cognee\\main.py"
# A logger OUTSIDE app.observability, exactly as cerebras_client / handlers use.
other = logging.getLogger("app.some_other_module")
other.setLevel(logging.INFO)
other.error("failed reading %s during cognify", secret_path)
assert bootstrap.get_captured_logs() == [], (
"ordinary app.* logs must not reach the OTel log pipeline"
)
# The sanitized correlated-log path IS the only thing that reaches export.
emit_correlated_log(
"operation retrieval.vector_search finished with status=error",
operation="retrieval.vector_search",
status="error",
)
logs = bootstrap.get_captured_logs()
assert logs, "emit_correlated_log should reach the OTel log pipeline"
bodies = [str(getattr(r.log_record, "body", "")) for r in logs]
assert any("retrieval.vector_search" in b for b in bodies)
assert all(secret_path not in b for b in bodies)
# --- record_event -----------------------------------------------------------
def test_record_event_does_not_raise_inside_operation(tmp_path):
bootstrap.initialize_observability(config=_local_config(tmp_path))
with observe_operation("rag.request"):
record_event("cache_hit", {"cache.state": "warm"})
spans = bootstrap.get_captured_spans()
assert spans[0].events, "expected the event to be attached to the span"
assert spans[0].events[0].name == "cache_hit"
|