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

+1 -3
View File
@@ -71,7 +71,6 @@ fn main() -> anyhow::Result<()> {
);
let dao: Arc<Mutex<Box<dyn ExifDao>>> = Arc::new(Mutex::new(Box::new(SqliteExifDao::new())));
let ctx = opentelemetry::Context::new();
let mut total_hashed = 0u64;
let mut total_missing = 0u64;
@@ -84,7 +83,7 @@ fn main() -> anyhow::Result<()> {
let rows = {
let mut guard = dao.lock().expect("Unable to lock ExifDao");
guard
.get_rows_missing_hash(&ctx, args.batch_size)
.get_rows_missing_hash(args.batch_size)
.map_err(|e| anyhow::anyhow!("DB error: {:?}", e))?
};
if rows.is_empty() {
@@ -128,7 +127,6 @@ fn main() -> anyhow::Result<()> {
match ident {
Some(id) => {
match guard.backfill_content_hash(
&ctx,
*library_id,
rel_path,
&id.content_hash,
+1 -4
View File
@@ -78,7 +78,6 @@ fn main() -> anyhow::Result<()> {
);
let dao: Arc<Mutex<Box<dyn ExifDao>>> = Arc::new(Mutex::new(Box::new(SqliteExifDao::new())));
let ctx = opentelemetry::Context::new();
let mut total_hashed = 0u64;
let mut total_missing = 0u64;
@@ -92,7 +91,7 @@ fn main() -> anyhow::Result<()> {
let rows = {
let mut guard = dao.lock().expect("Unable to lock ExifDao");
guard
.get_rows_missing_perceptual_hash(&ctx, args.batch_size)
.get_rows_missing_perceptual_hash(args.batch_size)
.map_err(|e| anyhow::anyhow!("DB error: {:?}", e))?
};
if rows.is_empty() {
@@ -137,7 +136,6 @@ fn main() -> anyhow::Result<()> {
match result {
FilePerceptualResult::Ok(id) => {
match guard.backfill_perceptual_hash(
&ctx,
*library_id,
rel_path,
Some(id.phash_64),
@@ -170,7 +168,6 @@ fn main() -> anyhow::Result<()> {
library_id
);
match guard.backfill_perceptual_hash(
&ctx,
*library_id,
rel_path,
Some(0),
+3 -8
View File
@@ -42,8 +42,6 @@ async fn main() -> Result<()> {
info!("Found {} calendar events", events.len());
let context = opentelemetry::Context::current();
// LocalLlm dispatches per LLM_BACKEND, so embeddings written here land
// in the same vector space the query side searches.
let llm = if args.generate_embeddings {
@@ -65,11 +63,8 @@ async fn main() -> Result<()> {
// Check if event exists
if args.skip_existing
&& let Ok(exists) = dao_instance.event_exists(
&context,
event.event_uid.as_deref().unwrap_or(""),
event.start_time,
)
&& let Ok(exists) = dao_instance
.event_exists(event.event_uid.as_deref().unwrap_or(""), event.start_time)
&& exists
{
skipped_count += 1;
@@ -120,7 +115,7 @@ async fn main() -> Result<()> {
source_file: Some(args.path.clone()),
};
match dao_instance.store_event(&context, insert_event) {
match dao_instance.store_event(insert_event) {
Ok(_) => inserted_count += 1,
Err(e) => {
pb.println(format!("store failed for '{}': {:?}", event.summary, e));
+1 -4
View File
@@ -37,8 +37,6 @@ async fn main() -> Result<()> {
info!("Found {} location records", locations.len());
let context = opentelemetry::Context::current();
let mut inserted_count = 0usize;
let mut skipped_count = 0usize;
let mut error_count = 0usize;
@@ -58,7 +56,6 @@ async fn main() -> Result<()> {
// Skip existing check if requested (makes import much slower)
if args.skip_existing
&& let Ok(exists) = dao_instance.location_exists(
&context,
location.timestamp,
location.latitude,
location.longitude,
@@ -87,7 +84,7 @@ async fn main() -> Result<()> {
// Batch insert entire chunk in single transaction
if !batch_inserts.is_empty() {
match dao_instance.store_locations_batch(&context, batch_inserts) {
match dao_instance.store_locations_batch(batch_inserts) {
Ok(count) => inserted_count += count,
Err(e) => {
pb.println(format!("batch insert failed: {:?}", e));
+2 -4
View File
@@ -41,7 +41,6 @@ async fn main() -> Result<()> {
// LocalLlm dispatches per LLM_BACKEND, so embeddings written here land
// in the same vector space the query side searches.
let llm = LocalLlm::from_env();
let context = opentelemetry::Context::current();
let mut inserted_count = 0usize;
let mut skipped_count = 0usize;
@@ -84,8 +83,7 @@ async fn main() -> Result<()> {
for (search, embedding_opt) in chunk.iter().zip(embeddings_result.iter()) {
// Check if search exists (optional for speed)
if args.skip_existing
&& let Ok(exists) =
dao_instance.search_exists(&context, search.timestamp, &search.query)
&& let Ok(exists) = dao_instance.search_exists(search.timestamp, &search.query)
&& exists
{
skipped_count += 1;
@@ -110,7 +108,7 @@ async fn main() -> Result<()> {
// Batch insert entire chunk in single transaction
if !batch_inserts.is_empty() {
match dao_instance.store_searches_batch(&context, batch_inserts) {
match dao_instance.store_searches_batch(batch_inserts) {
Ok(count) => inserted_count += count,
Err(e) => {
pb.println(format!("batch insert failed: {:?}", e));
+1 -2
View File
@@ -305,7 +305,6 @@ async fn main() -> anyhow::Result<()> {
return Ok(());
}
let cx = opentelemetry::Context::new();
let mut processed = 0usize;
let mut skipped = 0usize;
let mut errors = 0usize;
@@ -319,7 +318,7 @@ async fn main() -> anyhow::Result<()> {
let has_insight = insight_dao
.lock()
.unwrap()
.get_insight(&cx, relative)
.get_insight(relative)
.unwrap_or(None)
.is_some();
+1 -2
View File
@@ -128,7 +128,6 @@ async fn main() -> anyhow::Result<()> {
);
let dao: Arc<Mutex<Box<dyn ExifDao>>> = Arc::new(Mutex::new(Box::new(SqliteExifDao::new())));
let ctx = opentelemetry::Context::new();
// Encode the query up-front so the long image-encode loop doesn't
// race a slow query encode. Fails fast on a misspelled query.
@@ -168,7 +167,7 @@ async fn main() -> anyhow::Result<()> {
let rows = {
let mut guard = dao.lock().expect("dao lock");
guard
.list_rel_paths_for_library_page(&ctx, lib.id, PAGE, offset)
.list_rel_paths_for_library_page(lib.id, PAGE, offset)
.map_err(|e| anyhow::anyhow!("list rel_paths: {:?}", e))?
};
if rows.is_empty() {
+1 -2
View File
@@ -251,9 +251,8 @@ async fn main() -> Result<()> {
};
let mut dao = summary_dao.lock().expect("Unable to lock DailySummaryDao");
let context = opentelemetry::Context::new();
match dao.store_summary(&context, insert) {
match dao.store_summary(insert) {
Ok(_) => println!("✓ Saved to database"),
Err(e) => println!("✗ Database error: {:?}", e),
}