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:
1 parent
1c508cdabd
commit
b6deca2a52
55 files changed
+1942
-3852
No files matched your search
+12
-22
@@ -529,26 +529,24 @@ impl PersonaChatSession {
|
||||
if persona_id.is_empty() {
|
||||
return Err(PersonaChatError::UnknownPersona(String::new()));
|
||||
}
|
||||
let cx = opentelemetry::Context::current();
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
// Validate up front rather than letting the first turn 404: a
|
||||
// conversation row pointing at a persona that doesn't exist would be
|
||||
// a permanently dead entry in the list.
|
||||
let persona = dao
|
||||
.get_persona(&cx, user_id, persona_id)
|
||||
.get_persona(user_id, persona_id)
|
||||
.map_err(|e| PersonaChatError::Db(anyhow!("{e:?}")))?;
|
||||
if persona.is_none() {
|
||||
return Err(PersonaChatError::UnknownPersona(persona_id.to_string()));
|
||||
}
|
||||
dao.create_persona_chat(&cx, user_id, persona_id, Utc::now().timestamp_millis())
|
||||
dao.create_persona_chat(user_id, persona_id, Utc::now().timestamp_millis())
|
||||
.map_err(|e| PersonaChatError::Db(anyhow!("{e:?}")))
|
||||
}
|
||||
|
||||
/// Delete a conversation and its transcript outright.
|
||||
pub fn delete_conversation(&self, user_id: i32, conversation_id: &str) -> Result<()> {
|
||||
let cx = opentelemetry::Context::current();
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
dao.delete_persona_chat(&cx, user_id, conversation_id)
|
||||
dao.delete_persona_chat(user_id, conversation_id)
|
||||
.map_err(|e| anyhow!("failed to delete persona chat: {e:?}"))?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -565,10 +563,9 @@ impl PersonaChatSession {
|
||||
conversation_id: &str,
|
||||
branch_id: Option<u64>,
|
||||
) -> Result<PersonaChatHistoryView> {
|
||||
let cx = opentelemetry::Context::current();
|
||||
let row = {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
dao.get_persona_chat(&cx, user_id, conversation_id)
|
||||
dao.get_persona_chat(user_id, conversation_id)
|
||||
.map_err(|e| anyhow!("failed to load persona chat: {e:?}"))?
|
||||
};
|
||||
let Some(row) = row else {
|
||||
@@ -628,18 +625,17 @@ impl PersonaChatSession {
|
||||
return Err(PersonaChatError::UnknownConversation(conversation_id));
|
||||
}
|
||||
|
||||
let cx = opentelemetry::Context::current();
|
||||
// The persona comes from the stored conversation, not the request:
|
||||
// a transcript's voice is fixed when it is created, so a stale
|
||||
// client can't quietly swap it half-way through a thread.
|
||||
let (persona, persona_id) = {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
let row = dao
|
||||
.get_persona_chat(&cx, user_id, &conversation_id)
|
||||
.get_persona_chat(user_id, &conversation_id)
|
||||
.map_err(|e| PersonaChatError::Db(anyhow!("{e:?}")))?
|
||||
.ok_or_else(|| PersonaChatError::UnknownConversation(conversation_id.clone()))?;
|
||||
let persona = dao
|
||||
.get_persona(&cx, user_id, &row.persona_id)
|
||||
.get_persona(user_id, &row.persona_id)
|
||||
.map_err(|e| PersonaChatError::Db(anyhow!("{e:?}")))?
|
||||
.ok_or_else(|| PersonaChatError::UnknownPersona(row.persona_id.clone()))?;
|
||||
(persona, row.persona_id)
|
||||
@@ -742,10 +738,9 @@ impl PersonaChatSession {
|
||||
let _guard = lock.lock().await;
|
||||
|
||||
// Replay the active branch of the conversation tree.
|
||||
let cx = opentelemetry::Context::current();
|
||||
let row = {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
dao.get_persona_chat(&cx, user_id, &conversation_id)
|
||||
dao.get_persona_chat(user_id, &conversation_id)
|
||||
.map_err(|e| anyhow!("failed to load persona chat: {e:?}"))?
|
||||
};
|
||||
let row = row.ok_or_else(|| anyhow!("conversation not found"))?;
|
||||
@@ -935,7 +930,6 @@ impl PersonaChatSession {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
let rows = dao
|
||||
.update_persona_chat(
|
||||
&cx,
|
||||
user_id,
|
||||
&conversation_id,
|
||||
&json,
|
||||
@@ -958,7 +952,7 @@ impl PersonaChatSession {
|
||||
.unwrap_or_else(|| fallback_title(&messages));
|
||||
if !title.is_empty() {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
if let Err(e) = dao.set_persona_chat_title(&cx, user_id, &conversation_id, &title) {
|
||||
if let Err(e) = dao.set_persona_chat_title(user_id, &conversation_id, &title) {
|
||||
log::warn!("failed to store persona chat title: {e:?}");
|
||||
}
|
||||
}
|
||||
@@ -989,14 +983,13 @@ impl PersonaChatSession {
|
||||
/// Conversations that hold nothing but the seed are omitted too — the
|
||||
/// user has never actually said anything in them.
|
||||
pub fn list_conversations(&self, user_id: i32) -> Result<Vec<PersonaConversationSummary>> {
|
||||
let cx = opentelemetry::Context::current();
|
||||
let (rows, personas) = {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
let rows = dao
|
||||
.list_persona_chats(&cx, user_id)
|
||||
.list_persona_chats(user_id)
|
||||
.map_err(|e| anyhow!("failed to list persona chats: {e:?}"))?;
|
||||
let personas = dao
|
||||
.list_personas(&cx, user_id)
|
||||
.list_personas(user_id)
|
||||
.map_err(|e| anyhow!("failed to list personas: {e:?}"))?;
|
||||
(rows, personas)
|
||||
};
|
||||
@@ -1099,10 +1092,9 @@ impl PersonaChatSession {
|
||||
};
|
||||
let _guard = lock.lock().await;
|
||||
|
||||
let cx = opentelemetry::Context::current();
|
||||
let row = {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
dao.get_persona_chat(&cx, user_id, conversation_id)
|
||||
dao.get_persona_chat(user_id, conversation_id)
|
||||
.map_err(|e| anyhow!("failed to load persona chat: {e:?}"))?
|
||||
};
|
||||
let row = row.ok_or_else(|| anyhow!("conversation not found"))?;
|
||||
@@ -1121,7 +1113,6 @@ impl PersonaChatSession {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
let rows = dao
|
||||
.update_persona_chat(
|
||||
&cx,
|
||||
user_id,
|
||||
conversation_id,
|
||||
&json,
|
||||
@@ -1195,10 +1186,9 @@ impl PersonaChatSession {
|
||||
node_id: Option<u64>,
|
||||
viewing_leaf: Option<u64>,
|
||||
) -> Result<(Vec<crate::ai::llm_client::BranchLeafInfo>, u64)> {
|
||||
let cx = opentelemetry::Context::current();
|
||||
let row = {
|
||||
let mut dao = self.persona_dao.lock().expect("persona_dao poisoned");
|
||||
dao.get_persona_chat(&cx, user_id, conversation_id)
|
||||
dao.get_persona_chat(user_id, conversation_id)
|
||||
.map_err(|e| anyhow!("failed to load persona chat: {e:?}"))?
|
||||
};
|
||||
let row = row.ok_or_else(|| anyhow!("conversation not found"))?;
|
||||
|
||||
Reference in new issue
Block a user