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

+10 -16
View File
@@ -8,16 +8,15 @@
//! is parented onto the caller's span — the whole request shares the
//! caller's `trace_id`.
//!
//! 2. **No duplicate request span.** A handler that parents its operation span
//! through `otel::extract_context_from_request` nests it *under* the
//! middleware's root span (one tree) rather than re-parsing the header into
//! a second, sibling request span.
//! 2. **No duplicate request span.** A handler's `#[instrument]`ed operation
//! span nests *under* the middleware's root span (one tree) rather than
//! re-parsing the header into a second, sibling request span.
//!
//! One process-global subscriber + propagator per test binary (one-shot), so
//! this file holds a single test.
use actix_web::{web, App, HttpRequest, HttpResponse};
use opentelemetry::trace::{Tracer, TracerProvider};
use actix_web::{App, HttpResponse, web};
use opentelemetry::trace::TracerProvider;
use opentelemetry_sdk::propagation::TraceContextPropagator;
use opentelemetry_sdk::trace::{InMemorySpanExporter, SdkTracerProvider, SpanData};
use tracing_subscriber::layer::SubscriberExt;
@@ -27,12 +26,10 @@ use tracing_subscriber::util::SubscriberInitExt;
const TRACE_ID: &str = "0af7651916cd43dd8448eb211c80319c";
const REMOTE_PARENT: &str = "b7ad6b7169203331";
/// Mirrors the app's handler pattern: parent the operation span via
/// `extract_context_from_request` (which sources the middleware's root span).
async fn operation_handler(req: HttpRequest) -> HttpResponse {
let cx = image_api::otel::extract_context_from_request(&req);
let tracer = image_api::otel::global_tracer();
let _span = tracer.start_with_context("test.operation", &cx);
/// Mirrors the app's handler pattern: an `#[instrument]`ed operation span,
/// parented ambiently on the middleware's root span.
#[tracing::instrument(name = "test.operation", skip_all)]
async fn operation_handler() -> HttpResponse {
HttpResponse::Ok().finish()
}
@@ -65,10 +62,7 @@ async fn traceparent_header_nests_request_spans() {
let req = actix_web::test::TestRequest::get()
.uri("/op")
.insert_header((
"traceparent",
format!("00-{TRACE_ID}-{REMOTE_PARENT}-01"),
))
.insert_header(("traceparent", format!("00-{TRACE_ID}-{REMOTE_PARENT}-01")))
.to_request();
let _res = actix_web::test::call_and_read_body(&srv, req).await;