Tracing: DAO layer + handler spans on tracing, drop all Context params (#141)

trace_db_call no longer takes an OpenTelemetry Context: it opens a
db.<query_type>.<operation> span (same name via otel.name, same
db.query_type / db.operation attrs) on the caller's ambient tracing span
and runs the DAO body inside it. The cx / ctx / context parameter is gone
from every DAO trait method, impl and call site, and from the helpers and
background drains that only threaded it.

The remaining request-handler spans (files, tags, faces, image, video,
favorites, duplicates, memories) move to #[instrument]; the
Context::current_with_span / with_remote_span_context plumbing is gone, as
is extract_context_from_request (the tracing-actix-web root span covers
it). otel::set_span_attributes replaces BoxedSpan::set_attributes.

Background-job raw spans (thumbnails, video actors) are left for #142.

tests/otel_db_spans.rs pins name, attributes, status and nesting (across
an instrumented spawn); otel_traceparent now uses an #[instrument]
handler. CLAUDE.md documents the tracing conventions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-09-29 17:02:40 -04:00
1 parent 1c508cdabd
commit b6deca2a52
55 files changed
+1942 -3852

No files matched your search

+19 -3
View File
@@ -108,7 +108,7 @@ cargo run --bin create_user -- <username> <password>
- `image_exif`: Rich metadata (file_path + 16 EXIF fields: camera, GPS, dates, exposure settings)
**DAO Pattern:**
All database access goes through trait-based DAOs (e.g., `ExifDao`, `SqliteExifDao`). Connection pooling uses `Arc<Mutex<SqliteConnection>>`. All DB operations are traced with OpenTelemetry in release builds.
All database access goes through trait-based DAOs (e.g., `ExifDao`, `SqliteExifDao`). Connection pooling uses `Arc<Mutex<SqliteConnection>>`. Every DAO method runs inside `otel::trace_db_call` (a `db.<type>.<op>` span); DAO methods take no tracing context.
**Key DAO Methods:**
- `store_exif()`, `get_exif()`, `get_exif_batch()`: EXIF CRUD operations
@@ -563,8 +563,24 @@ Always use `is_valid_full_path(&base_path, &requested_path, check_exists)` to pr
**File Type Detection:**
Centralized in `file_types.rs` with constants `IMAGE_EXTENSIONS` and `VIDEO_EXTENSIONS`. Provides both `Path` and `DirEntry` variants for performance.
**OpenTelemetry Tracing:**
All database operations and HTTP handlers wrapped in spans. In release builds, exports to OTLP endpoint via `OTLP_OTLS_ENDPOINT`. Debug builds use basic logger.
**Tracing (`tracing` + `tracing-opentelemetry`):**
Spans are `tracing` spans in every build; `otel::init_tracing` installs the
subscriber and exports over OTLP when `OTLP_OTLS_ENDPOINT` is set. The
`tracing-actix-web` middleware creates the per-request root span (and honors
an incoming `traceparent`). Conventions:
- **No context threading.** Never pass an `opentelemetry::Context` down a
call chain — spans parent on the ambient span. Handlers and feature fns use
`#[tracing::instrument(name = "...", skip_all)]`; attributes/status go
through `tracing_opentelemetry::OpenTelemetrySpanExt` (`set_attribute`,
`set_status`) on `tracing::Span::current()`.
- **Carry the span across `tokio::spawn`.** Tracing context is thread-local;
wrap the spawned future with `.instrument(span)` or its spans orphan onto a
fresh trace (pinned by `tests/otel_propagation.rs`).
- **Mid-function sub-spans** (e.g. an agentic loop): create an `info_span!`
and `.instrument(span.clone())` each await that should nest under it —
never hold `span.enter()` across an `.await`.
- DB: `otel::trace_db_call`; LLM: `otel::start_llm_request_span` (injects
`traceparent` downstream).
**Memory Exclusion:**
`PathExcluder` in `memories.rs` filters out directories from memories API via `EXCLUDED_DIRS` environment variable (comma-separated paths or substring patterns). The same excluder is applied to face-detection candidates (`face_watch::filter_excluded`) so junk directories like `@eaDir` / `.thumbnails` don't burn detect calls on Apollo.