Skip to content

feat: native OpenTelemetry instrumentation (optional, off by default)#352

Open
gloryfromca wants to merge 3 commits into
mainfrom
feat/otel-instrumentation
Open

feat: native OpenTelemetry instrumentation (optional, off by default)#352
gloryfromca wants to merge 3 commits into
mainfrom
feat/otel-instrumentation

Conversation

@gloryfromca

Copy link
Copy Markdown
Collaborator

What

Native, opt-in OpenTelemetry instrumentation for EverOS memory operations. Pure OTLP/HTTP — vendor-neutral (Langfuse, an OTel Collector, any OTLP backend); EverOS ships no vendor SDK. Off by default; enable via [observability].

Spans emitted

Operation Span Type
POST /memory/add · /flush everos.memory.add / .flush span
episode extraction everos.extract generation (model + tokens → Langfuse cost)
markdown persist everos.persist.markdown span
POST /memory/search everos.memory.search retriever
recall / rank phases everos.search.recall / .rank retriever / span
OME strategy everos.ome.<strategy> agent
reflection consolidate everos.reflect.consolidate generation

Plus recall-quality scores (recall_top_score / recall_hit) pushed to Langfuse.

Highlights

  • Off by default, zero-overhead when disabled; [otel] is an optional extra, guarded imports (no-op if absent).
  • Token capture without touching everalgo — an LLM-client wrapper + embedding provider record gen_ai.* usage onto the active span.
  • Non-blocking recall scores — bounded-queue background worker POSTs to Langfuse off the request path.
  • Privacycapture_content off by default (metadata only); redaction hook + truncation when on.
  • Distributed tracing — continues an inbound traceparent; OME strategies fanned out from a request nest under that request's trace (traceparent threaded across the APScheduler boundary). request_id kept independent of trace_id.

Structure

3 commits: (1) tracing chassis + request-id propagation, (2) LLM/embedding token capture, (3) memory-op instrumentation + OME trace linking.

Verification

  • 1648 unit + integration tests pass; make lint clean (ruff, import-linter, datetime, openapi).
  • Live-verified against real Langfuse: full trace tree (flush → extract w/ real gpt-4.1-mini tokens + persist + 5 OME agent spans linked under it), search recall/rank + real recall scores, RETRIEVER/AGENT/GENERATION types rendered, content capture — all confirmed.

🤖 Generated with Claude Code

@gloryfromca
gloryfromca requested a review from cyfyifanchen July 23, 2026 12:47
zhanghui and others added 3 commits July 23, 2026 20:47
Optional, off-by-default native OpenTelemetry export (the [otel] extra),
wired as chassis so call sites never branch on config:

- ObservabilitySettings ([observability]) — enabled / endpoint / headers /
  sample_rate / capture_content / langfuse_* / recall_hit_threshold; langfuse
  creds derive the OTLP endpoint + Basic-auth header.
- core.observability.tracing: TracerProvider lifecycle (module-local, no-op
  when off/absent), memory_span helper stamping the langfuse.* contract,
  set_generation_usage, privacy-gated capture_input/output (redaction +
  truncation), non-blocking recall-score sink, W3C traceparent in/out helpers.
- TracingLifespanProvider builds provider + score sink at startup.
- RequestIdMiddleware: per-request id (state + contextvar + structlog +
  X-Request-Id) and continues an upstream traceparent when present; managers
  read the propagated id via resolve_request_id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface gen_ai.* model + token attributes onto the active span so Langfuse
can compute cost — without touching everalgo:

- UsageRecordingClient wraps the LLM client and records response.usage after
  each chat(); get_llm_client composes it over the existing _LoggingLLMClient
  only when observability is enabled (disabled default stays overhead-free).
- OpenAIEmbeddingProvider records its response.usage (input tokens) onto the
  active span too.

Tokens land on the everos.extract / everos.reflect.consolidate generation
spans and the search embedding recall; no-op when tracing is off.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Open spans at the memory hot paths (all no-op when tracing is off):

- add / flush (service.memorize), extract + persist.markdown (user pipeline).
- search: everos.memory.search retriever + a uniform recall / rank
  decomposition across keyword / vector / hybrid / agentic (manager, agentic
  modules, cross-encoder callbacks); query-embedding tokens land on recall.
- recall quality: top_score / hit on the search span, plus recall_top_score /
  recall_hit pushed to Langfuse scores via the bounded-queue sink (method
  tagged; off the request path).
- OME: everos.ome.<strategy> agent span + everos.reflect.consolidate
  generation; a W3C traceparent captured at enqueue is threaded through the
  APScheduler job and re-attached in the Runner, so strategies fanned out
  from a request nest under that request's trace.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gloryfromca
gloryfromca force-pushed the feat/otel-instrumentation branch from 7ee23b1 to 357f619 Compare July 23, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants