Address PR review: inline propagation helpers, always include traceparent
- Remove traceparent_from_span and context_from_traceparent helper
functions — each had one call site and added indirection without
meaningful abstraction
- Inline the W3C propagation logic directly at each call site
- Always extract and pass traceparent regardless of Sentry DSN, since
OTEL spans exist independently of Sentry
https://claude.ai/code/session_01Tbgz29e8A9KS4Bh94skkFX
diff --git a/Cargo.lock b/Cargo.lock
index b35f36a..1fbda02 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2554,6 +2554,8 @@ dependencies = [
"jiff",
"miette",
"mlua",
+ "opentelemetry",
+ "opentelemetry_sdk",
"quire-core",
"reqwest",
"sentry",
@@ -2608,6 +2610,8 @@ dependencies = [
"jiff",
"miette",
"mlua",
+ "opentelemetry",
+ "opentelemetry_sdk",
"petgraph",
"predicates",
"quire-core",
@@ -2626,6 +2630,7 @@ dependencies = [
"tokio",
"tower",
"tracing",
+ "tracing-opentelemetry",
"uuid",
"walkdir",
]
diff --git a/quire-ci/Cargo.toml b/quire-ci/Cargo.toml
index a99f364..76a758b 100644
--- a/quire-ci/Cargo.toml
+++ b/quire-ci/Cargo.toml
@@ -18,5 +18,7 @@ serde_json = { workspace = true }
tempfile = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread"] }
+opentelemetry = { workspace = true }
+opentelemetry_sdk = { workspace = true }
tracing = { workspace = true }
tracing-opentelemetry = { workspace = true }
diff --git a/quire-ci/src/main.rs b/quire-ci/src/main.rs
index 89017e6..16d2d93 100644
--- a/quire-ci/src/main.rs
+++ b/quire-ci/src/main.rs
@@ -17,6 +17,7 @@ use quire_core::ci::run::RunMeta;
use quire_core::ci::runtime::{Runtime, RuntimeError, RuntimeEvent, RuntimeHandle};
use quire_core::fennel::FennelError;
use quire_core::secret::{Error as SecretError, Result as SecretResult, SecretRegistry};
+use opentelemetry::propagation::TextMapPropagator as _;
use quire_core::telemetry::{self, FmtMode, MietteLayer};
use tracing_opentelemetry::OpenTelemetrySpanExt as _;
use reqwest::header::{AUTHORIZATION, HeaderMap, HeaderValue};
@@ -368,7 +369,11 @@ fn main() -> Result<()> {
let run_span =
tracing::info_span!("quire.ci.run", sha = %meta.sha, r#ref = %meta.r#ref);
if let Some(tp) = sentry_ctx.traceparent.as_deref() {
- run_span.set_parent(telemetry::context_from_traceparent(tp));
+ let mut carrier = std::collections::HashMap::new();
+ carrier.insert("traceparent".to_string(), tp.to_string());
+ run_span.set_parent(
+ opentelemetry_sdk::propagation::TraceContextPropagator::new().extract(&carrier),
+ );
}
let _run_span = run_span.entered();
diff --git a/quire-core/src/telemetry.rs b/quire-core/src/telemetry.rs
index ecac6aa..01731fb 100644
--- a/quire-core/src/telemetry.rs
+++ b/quire-core/src/telemetry.rs
@@ -4,9 +4,7 @@ use std::io::IsTerminal;
use std::sync::Arc;
use miette::IntoDiagnostic;
-use opentelemetry::propagation::TextMapPropagator as _;
use opentelemetry::trace::TracerProvider as _;
-use tracing_opentelemetry::OpenTelemetrySpanExt as _;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::Layer;
use tracing_subscriber::layer::SubscriberExt;
@@ -201,24 +199,6 @@ impl Drop for TracingGuard {
}
}
-/// Extract the W3C traceparent from a tracing span's OTEL context.
-/// Returns None when the span has no valid OTEL context (e.g. OTEL not initialised).
-pub fn traceparent_from_span(span: &tracing::Span) -> Option<String> {
- let propagator = opentelemetry_sdk::propagation::TraceContextPropagator::new();
- let cx = span.context();
- let mut carrier = std::collections::HashMap::new();
- propagator.inject_context(&cx, &mut carrier);
- carrier.remove("traceparent")
-}
-
-/// Decode a W3C traceparent string into an OTEL context suitable for
-/// passing to [`tracing_opentelemetry::OpenTelemetrySpanExt::set_parent`].
-pub fn context_from_traceparent(traceparent: &str) -> opentelemetry::Context {
- let propagator = opentelemetry_sdk::propagation::TraceContextPropagator::new();
- let mut carrier = std::collections::HashMap::new();
- carrier.insert("traceparent".to_string(), traceparent.to_string());
- propagator.extract(&carrier)
-}
/// Initialize the global tracing subscriber with `QUIRE_LOG`-driven filtering,
/// a stderr fmt layer per `fmt_mode`, the `sentry-tracing` bridge, the
diff --git a/quire-server/Cargo.toml b/quire-server/Cargo.toml
index 84925d5..42fc8ce 100644
--- a/quire-server/Cargo.toml
+++ b/quire-server/Cargo.toml
@@ -28,7 +28,10 @@ serde = { workspace = true }
serde_json = { workspace = true }
tempfile = { workspace = true }
thiserror = { workspace = true }
+opentelemetry = { workspace = true }
+opentelemetry_sdk = { workspace = true }
tracing = { workspace = true }
+tracing-opentelemetry = { workspace = true }
askama = "*"
axum = "*"
diff --git a/quire-server/src/ci/mod.rs b/quire-server/src/ci/mod.rs
index e59511f..0487ec0 100644
--- a/quire-server/src/ci/mod.rs
+++ b/quire-server/src/ci/mod.rs
@@ -11,7 +11,8 @@ pub use quire_core::ci::pipeline::{
pub use quire_core::ci::run::ApiSession;
pub use quire_core::ci::run::RunMeta;
pub use quire_core::ci::{pipeline, registration, runtime};
-use quire_core::telemetry;
+use opentelemetry::propagation::TextMapPropagator as _;
+use tracing_opentelemetry::OpenTelemetrySpanExt as _;
pub use run::{Executor, Run, RunState, Runs, materialize_workspace, reconcile_orphans};
/// A resolved commit reference.
@@ -168,10 +169,12 @@ fn run_ref(ctx: &TriggerContext<'_>, pushed_at: jiff::Timestamp, push_ref: &Push
let session = ApiSession::new(ctx.port);
let span = tracing::info_span!("quire.ci.run", repo = %ctx.event_repo);
- let traceparent = ctx
- .sentry_dsn
- .as_ref()
- .and_then(|_| telemetry::traceparent_from_span(&span));
+ let traceparent = {
+ let mut carrier = std::collections::HashMap::new();
+ opentelemetry_sdk::propagation::TraceContextPropagator::new()
+ .inject_context(&span.context(), &mut carrier);
+ carrier.remove("traceparent")
+ };
let _guard = span.enter();
sentry::with_scope(