Otel: dedupe LLM span error/status + traceparent helpers (#130 follow-up)
Addresses the P2 refactoring follow-ups parked on issue #130: - otel::with_traceparent(builder, &SpanContext) — one shared W3C traceparent injector. Replaces the 4-line inline header loop in llamacpp (3x) and openrouter (3x) and removes ollama's private inject_traceparent method (4 call sites now use the shared helper). Takes &SpanContext (not &dyn Span) because the Span trait is not dyn compatible in opentelemetry 0.31. - otel::record_http_failure(span, status, message) and otel::set_http_status(span, status) — collapse the repeated 'set http.status_code attribute + set_status(Status::error)' boilerplate across all three clients (~10 sites). Net -45 lines. The remaining if-let-Some(span.as_mut()) guards (token attributes, parse-failure status) stay inline rather than growing a SpanHandle wrapper type for a pattern that's already readable.
This commit is contained in:
1 parent
696d9fa8f3
commit
10ed84d7b4
4 files changed
+108
-153
No files matched your search
+22
-44
@@ -23,7 +23,7 @@
|
||||
use anyhow::Context as _;
|
||||
use anyhow::{Result, anyhow, bail};
|
||||
use async_trait::async_trait;
|
||||
use opentelemetry::trace::{Span, Status, TraceContextExt};
|
||||
use opentelemetry::trace::{Span, Status};
|
||||
use opentelemetry::{Context, KeyValue};
|
||||
use reqwest::Client;
|
||||
use serde::Deserialize;
|
||||
@@ -523,11 +523,7 @@ impl LlamaCppClient {
|
||||
let _gpu = crate::ai::gpu::llm_lease().await;
|
||||
let mut request = self.client.post(&url).json(&Value::Object(body));
|
||||
if let Some(s) = span.as_mut() {
|
||||
for (k, v) in crate::otel::traceparent_headers(
|
||||
&Context::new().with_remote_span_context(s.span_context().clone()),
|
||||
) {
|
||||
request = request.header(k, v);
|
||||
}
|
||||
request = crate::otel::with_traceparent(request, s.span_context());
|
||||
}
|
||||
let resp = match request.send().await {
|
||||
Ok(r) => r,
|
||||
@@ -541,21 +537,15 @@ impl LlamaCppClient {
|
||||
|
||||
if !resp.status().is_success() {
|
||||
let status = resp.status();
|
||||
if let Some(s) = span.as_mut() {
|
||||
s.set_attribute(KeyValue::new("http.status_code", status.as_u16() as i64));
|
||||
s.set_status(Status::error(format!(
|
||||
"llama-swap chat request failed: {status}"
|
||||
)));
|
||||
}
|
||||
crate::otel::record_http_failure(
|
||||
span.as_deref_mut(),
|
||||
status.as_u16(),
|
||||
&format!("llama-swap chat request failed: {status}"),
|
||||
);
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
bail!("llama-swap chat request failed: {} — {}", status, body);
|
||||
}
|
||||
if let Some(s) = span.as_mut() {
|
||||
s.set_attribute(KeyValue::new(
|
||||
"http.status_code",
|
||||
resp.status().as_u16() as i64,
|
||||
));
|
||||
}
|
||||
crate::otel::set_http_status(span.as_deref_mut(), resp.status().as_u16());
|
||||
|
||||
let parsed: Value = resp.json().await.context("parsing chat response")?;
|
||||
let choice = parsed
|
||||
@@ -700,11 +690,7 @@ impl LlmClient for LlamaCppClient {
|
||||
// below so the lease spans the whole generation, not just the send.
|
||||
let gpu = crate::ai::gpu::llm_lease().await;
|
||||
let mut request = self.client.post(&url).json(&Value::Object(body));
|
||||
for (k, v) in crate::otel::traceparent_headers(
|
||||
&Context::new().with_remote_span_context(span.span_context().clone()),
|
||||
) {
|
||||
request = request.header(k, v);
|
||||
}
|
||||
request = crate::otel::with_traceparent(request, span.span_context());
|
||||
let resp = request
|
||||
.send()
|
||||
.await
|
||||
@@ -712,17 +698,15 @@ impl LlmClient for LlamaCppClient {
|
||||
|
||||
if !resp.status().is_success() {
|
||||
let status = resp.status();
|
||||
span.set_attribute(KeyValue::new("http.status_code", status.as_u16() as i64));
|
||||
span.set_status(Status::error(format!(
|
||||
"llama-swap stream request failed: {status}"
|
||||
)));
|
||||
crate::otel::record_http_failure(
|
||||
Some(&mut span),
|
||||
status.as_u16(),
|
||||
&format!("llama-swap stream request failed: {status}"),
|
||||
);
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
bail!("llama-swap stream request failed: {} — {}", status, body);
|
||||
}
|
||||
span.set_attribute(KeyValue::new(
|
||||
"http.status_code",
|
||||
resp.status().as_u16() as i64,
|
||||
));
|
||||
crate::otel::set_http_status(Some(&mut span), resp.status().as_u16());
|
||||
|
||||
let byte_stream = resp.bytes_stream();
|
||||
let stream = async_stream::stream! {
|
||||
@@ -860,11 +844,7 @@ impl LlmClient for LlamaCppClient {
|
||||
});
|
||||
|
||||
let mut request = self.client.post(&url).json(&body);
|
||||
for (k, v) in crate::otel::traceparent_headers(
|
||||
&Context::new().with_remote_span_context(span.span_context().clone()),
|
||||
) {
|
||||
request = request.header(k, v);
|
||||
}
|
||||
request = crate::otel::with_traceparent(request, span.span_context());
|
||||
let resp = match request.send().await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
@@ -875,17 +855,15 @@ impl LlmClient for LlamaCppClient {
|
||||
|
||||
if !resp.status().is_success() {
|
||||
let status = resp.status();
|
||||
span.set_attribute(KeyValue::new("http.status_code", status.as_u16() as i64));
|
||||
span.set_status(Status::error(format!(
|
||||
"llama-swap embedding request failed: {status}"
|
||||
)));
|
||||
crate::otel::record_http_failure(
|
||||
Some(&mut span),
|
||||
status.as_u16(),
|
||||
&format!("llama-swap embedding request failed: {status}"),
|
||||
);
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
bail!("llama-swap embedding request failed: {} — {}", status, body);
|
||||
}
|
||||
span.set_attribute(KeyValue::new(
|
||||
"http.status_code",
|
||||
resp.status().as_u16() as i64,
|
||||
));
|
||||
crate::otel::set_http_status(Some(&mut span), resp.status().as_u16());
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct EmbedResponse {
|
||||
|
||||
Reference in new issue
Block a user