diff --git a/CLAUDE.md b/CLAUDE.md index c95e9d9..32424cc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -581,6 +581,16 @@ an incoming `traceparent`). Conventions: never hold `span.enter()` across an `.await`. - DB: `otel::trace_db_call`; LLM: `otel::start_llm_request_span` (injects `traceparent` downstream). +- **`RUST_LOG` gates spans, not just logs.** The subscriber's single + `EnvFilter` sits in front of both the console and the OTel layer, so a span + below the filter level is never created: it's missing from the export, it + breaks the parent chain for its children, and an `llm.request` below it + sends no `traceparent`. Every span in the codebase is `info` level, so + `RUST_LOG=info` or `debug` (the supported range) exports everything; + `warn`/`error` silently turns tracing off. Per-target overrides like + `RUST_LOG=info,image_api::otel=warn` drop just those spans (here: DB and + LLM). If export ever needs to be independent of console verbosity, give + the OTel layer its own per-layer filter in `otel::init_tracing`. **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. @@ -665,7 +675,7 @@ GIFS_DIRECTORY=/path/to/gifs # Video GIF thumbnails BIND_URL=0.0.0.0:8080 # Server binding CORS_ALLOWED_ORIGINS=http://localhost:3000 SECRET_KEY=your-secret-key-here # JWT signing secret -RUST_LOG=info # Log level +RUST_LOG=info # Log level; also gates span export (keep at info/debug, see "Tracing") EXCLUDED_DIRS=/private,/archive # Comma-separated paths to exclude from memories ``` diff --git a/src/otel.rs b/src/otel.rs index ee9235e..4f1b756 100644 --- a/src/otel.rs +++ b/src/otel.rs @@ -55,6 +55,9 @@ pub fn init_tracing() { let tracer = tracer_provider.tracer("image-server"); global::set_tracer_provider(tracer_provider); + // One EnvFilter in front of BOTH layers: `RUST_LOG` also decides which + // spans exist for export. All spans are `info`, so keep it at info/debug + // (see CLAUDE.md "Tracing"); `warn` turns span export off. tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env()