mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-01 15:00:33 +00:00
This backports #1049, which was already approved on master. ## Motivation Support the latest OpenTelemetry specification ## Solution In order to support the latest spec, this patch makes the following breaking API changes: * Update `opentelemetry` to 0.10.x * Update `CompatSpan` to reflect changes to `Span` trait * Record `u64` values as strings as they are no longer supported in OpenTelemetry. Additionally the following non-public api, doc, and example changes: * Update examples and docs to use new simplified pipeline builder. * As `opentelemetry::api` no longer exports trace types, internally use `opentelemetry::trace as otel` to disambiguate from tracing types. * Remove `rand` dependency as it is no longer needed Co-authored-by: Eliza Weisman <eliza@buoyant.io> # Conflicts: # examples/examples/opentelemetry-remote-context.rs # tracing-opentelemetry/Cargo.toml # tracing-opentelemetry/src/layer.rs # tracing-opentelemetry/src/span_ext.rs # tracing-opentelemetry/src/tracer.rs
This commit is contained in:
parent
692c56f630
commit
642ad19d62
@ -52,5 +52,5 @@ inferno = "0.10.0"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
# opentelemetry example
|
||||
opentelemetry = { version = "0.8", default-features = false, features = ["trace"] }
|
||||
opentelemetry-jaeger = "0.7"
|
||||
opentelemetry = { version = "0.10", default-features = false, features = ["trace"] }
|
||||
opentelemetry-jaeger = "0.9"
|
||||
|
@ -1,13 +1,14 @@
|
||||
use opentelemetry::{api, api::HttpTextFormat};
|
||||
use opentelemetry::sdk::propagation::B3Propagator;
|
||||
use opentelemetry::{global, Context};
|
||||
use std::collections::HashMap;
|
||||
use tracing::span;
|
||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::Registry;
|
||||
|
||||
fn make_request(_cx: api::Context) {
|
||||
fn make_request(_cx: Context) {
|
||||
// perform external request after injecting context
|
||||
// e.g. if there are request headers that impl `opentelemetry::api::Carrier`
|
||||
// e.g. if there are request headers that impl `opentelemetry::propagation::Injector`
|
||||
// then `propagator.inject_context(cx, request.headers_mut())`
|
||||
}
|
||||
|
||||
@ -22,14 +23,15 @@ fn build_example_carrier() -> HashMap<String, String> {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Set a format for propagating context. This MUST be provided, as the default is a no-op.
|
||||
global::set_text_map_propagator(B3Propagator::new());
|
||||
let subscriber = Registry::default().with(tracing_opentelemetry::layer());
|
||||
|
||||
// Propagator can be swapped with trace context propagator binary propagator, etc.
|
||||
let propagator = api::B3Propagator::new();
|
||||
|
||||
tracing::subscriber::with_default(subscriber, || {
|
||||
// Extract from request headers, or any type that impls `opentelemetry::api::Carrier`
|
||||
let parent_context = propagator.extract(&build_example_carrier());
|
||||
// Extract context from request headers
|
||||
let parent_context = global::get_text_map_propagator(|propagator| {
|
||||
propagator.extract(&build_example_carrier())
|
||||
});
|
||||
|
||||
// Generate tracing span as usual
|
||||
let app_root = span!(tracing::Level::INFO, "app_start");
|
||||
|
@ -1,6 +1,4 @@
|
||||
use opentelemetry::api::Provider;
|
||||
use opentelemetry::sdk;
|
||||
use std::{thread, time::Duration};
|
||||
use std::{error::Error, thread, time::Duration};
|
||||
use tracing::{span, trace, warn};
|
||||
use tracing_attributes::instrument;
|
||||
use tracing_subscriber::prelude::*;
|
||||
@ -16,34 +14,15 @@ fn expensive_work() -> &'static str {
|
||||
"success"
|
||||
}
|
||||
|
||||
fn init_tracer() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let exporter = opentelemetry_jaeger::Exporter::builder()
|
||||
.with_agent_endpoint("127.0.0.1:6831".parse().unwrap())
|
||||
.with_process(opentelemetry_jaeger::Process {
|
||||
service_name: "report_example".to_string(),
|
||||
tags: Vec::new(),
|
||||
})
|
||||
.init()?;
|
||||
let provider = sdk::Provider::builder()
|
||||
.with_simple_exporter(exporter)
|
||||
.with_config(sdk::Config {
|
||||
default_sampler: Box::new(sdk::Sampler::AlwaysOn),
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
let tracer = provider.get_tracer("tracing");
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
||||
let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline()
|
||||
.with_service_name("report_example")
|
||||
.install()?;
|
||||
let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
tracing_subscriber::registry()
|
||||
.with(opentelemetry)
|
||||
.try_init()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
init_tracer()?;
|
||||
|
||||
let root = span!(tracing::Level::INFO, "app_start", work_units = 2);
|
||||
let _enter = root.enter();
|
||||
|
||||
|
@ -22,12 +22,11 @@ edition = "2018"
|
||||
default = ["tracing-log"]
|
||||
|
||||
[dependencies]
|
||||
opentelemetry = { version = "0.8", default-features = false, features = ["trace"] }
|
||||
rand = "0.7"
|
||||
opentelemetry = { version = "0.10", default-features = false, features = ["trace"] }
|
||||
tracing = { path = "../tracing", version = "0.1" }
|
||||
tracing-core = { path = "../tracing-core", version = "0.1" }
|
||||
tracing-subscriber = { path = "../tracing-subscriber", version = "0.2", default-features = false, features = ["registry"] }
|
||||
tracing-log = { path = "../tracing-log", version = "0.1", default-features = false, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
opentelemetry-jaeger = "0.7"
|
||||
opentelemetry-jaeger = "0.9"
|
||||
|
@ -59,22 +59,25 @@ The crate provides the following types:
|
||||
### Basic Usage
|
||||
|
||||
```rust
|
||||
use opentelemetry::{api::Provider, sdk};
|
||||
use opentelemetry::exporter::trace::stdout;
|
||||
use tracing::{error, span};
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::Registry;
|
||||
|
||||
fn main() {
|
||||
// Create a new tracer
|
||||
let tracer = sdk::Provider::default().get_tracer("component_name");
|
||||
// Install a new OpenTelemetry trace pipeline
|
||||
let (tracer, _uninstall) = stdout::new_pipeline().install();
|
||||
|
||||
// Create a new OpenTelemetry tracing layer
|
||||
// Create a tracing layer with the configured tracer
|
||||
let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
|
||||
// Use the tracing subscriber `Registry`, or any other subscriber
|
||||
// that impls `LookupSpan`
|
||||
let subscriber = Registry::default().with(telemetry);
|
||||
|
||||
// Trace executed code
|
||||
tracing::subscriber::with_default(subscriber, || {
|
||||
// Spans will be sent to the configured OpenTelemetry exporter
|
||||
let root = span!(tracing::Level::TRACE, "app_start", work_units = 2);
|
||||
let _enter = root.enter();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::PreSampledTracer;
|
||||
use opentelemetry::api::{self, Context as OtelContext, TraceContextExt};
|
||||
use opentelemetry::{trace as otel, trace::TraceContextExt, Context as OtelContext, Key, KeyValue};
|
||||
use std::any::TypeId;
|
||||
use std::fmt;
|
||||
use std::marker;
|
||||
@ -27,12 +27,12 @@ pub struct OpenTelemetryLayer<S, T> {
|
||||
_registry: marker::PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S> Default for OpenTelemetryLayer<S, api::NoopTracer>
|
||||
impl<S> Default for OpenTelemetryLayer<S, otel::NoopTracer>
|
||||
where
|
||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
OpenTelemetryLayer::new(api::NoopTracer {})
|
||||
OpenTelemetryLayer::new(otel::NoopTracer::new())
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ where
|
||||
/// let subscriber = Registry::default().with(tracing_opentelemetry::layer());
|
||||
/// # drop(subscriber);
|
||||
/// ```
|
||||
pub fn layer<S>() -> OpenTelemetryLayer<S, api::NoopTracer>
|
||||
pub fn layer<S>() -> OpenTelemetryLayer<S, otel::NoopTracer>
|
||||
where
|
||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||
{
|
||||
@ -67,7 +67,7 @@ pub(crate) struct WithContext(
|
||||
fn(
|
||||
&tracing::Dispatch,
|
||||
&span::Id,
|
||||
f: &mut dyn FnMut(&mut api::SpanBuilder, &dyn PreSampledTracer),
|
||||
f: &mut dyn FnMut(&mut otel::SpanBuilder, &dyn PreSampledTracer),
|
||||
),
|
||||
);
|
||||
|
||||
@ -78,34 +78,34 @@ impl WithContext {
|
||||
&self,
|
||||
dispatch: &'a tracing::Dispatch,
|
||||
id: &span::Id,
|
||||
mut f: impl FnMut(&mut api::SpanBuilder, &dyn PreSampledTracer),
|
||||
mut f: impl FnMut(&mut otel::SpanBuilder, &dyn PreSampledTracer),
|
||||
) {
|
||||
(self.0)(dispatch, id, &mut f)
|
||||
}
|
||||
}
|
||||
|
||||
fn str_to_span_kind(s: &str) -> Option<api::SpanKind> {
|
||||
fn str_to_span_kind(s: &str) -> Option<otel::SpanKind> {
|
||||
if s.eq_ignore_ascii_case("SERVER") {
|
||||
Some(api::SpanKind::Server)
|
||||
Some(otel::SpanKind::Server)
|
||||
} else if s.eq_ignore_ascii_case("CLIENT") {
|
||||
Some(api::SpanKind::Client)
|
||||
Some(otel::SpanKind::Client)
|
||||
} else if s.eq_ignore_ascii_case("PRODUCER") {
|
||||
Some(api::SpanKind::Producer)
|
||||
Some(otel::SpanKind::Producer)
|
||||
} else if s.eq_ignore_ascii_case("CONSUMER") {
|
||||
Some(api::SpanKind::Consumer)
|
||||
Some(otel::SpanKind::Consumer)
|
||||
} else if s.eq_ignore_ascii_case("INTERNAL") {
|
||||
Some(api::SpanKind::Internal)
|
||||
Some(otel::SpanKind::Internal)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct SpanEventVisitor<'a>(&'a mut api::Event);
|
||||
struct SpanEventVisitor<'a>(&'a mut otel::Event);
|
||||
|
||||
impl<'a> field::Visit for SpanEventVisitor<'a> {
|
||||
/// Record events on the underlying OpenTelemetry [`Span`] from `bool` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_bool(&mut self, field: &field::Field, value: bool) {
|
||||
match field.name() {
|
||||
"message" => self.0.name = value.to_string(),
|
||||
@ -113,14 +113,14 @@ impl<'a> field::Visit for SpanEventVisitor<'a> {
|
||||
#[cfg(feature = "tracing-log")]
|
||||
name if name.starts_with("log.") => (),
|
||||
name => {
|
||||
self.0.attributes.push(api::KeyValue::new(name, value));
|
||||
self.0.attributes.push(KeyValue::new(name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record events on the underlying OpenTelemetry [`Span`] from `i64` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_i64(&mut self, field: &field::Field, value: i64) {
|
||||
match field.name() {
|
||||
"message" => self.0.name = value.to_string(),
|
||||
@ -128,29 +128,14 @@ impl<'a> field::Visit for SpanEventVisitor<'a> {
|
||||
#[cfg(feature = "tracing-log")]
|
||||
name if name.starts_with("log.") => (),
|
||||
name => {
|
||||
self.0.attributes.push(api::KeyValue::new(name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record events on the underlying OpenTelemetry [`Span`] from `u64` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
fn record_u64(&mut self, field: &field::Field, value: u64) {
|
||||
match field.name() {
|
||||
"message" => self.0.name = value.to_string(),
|
||||
// Skip fields that are actually log metadata that have already been handled
|
||||
#[cfg(feature = "tracing-log")]
|
||||
name if name.starts_with("log.") => (),
|
||||
name => {
|
||||
self.0.attributes.push(api::KeyValue::new(name, value));
|
||||
self.0.attributes.push(KeyValue::new(name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record events on the underlying OpenTelemetry [`Span`] from `&str` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_str(&mut self, field: &field::Field, value: &str) {
|
||||
match field.name() {
|
||||
"message" => self.0.name = value.to_string(),
|
||||
@ -158,7 +143,9 @@ impl<'a> field::Visit for SpanEventVisitor<'a> {
|
||||
#[cfg(feature = "tracing-log")]
|
||||
name if name.starts_with("log.") => (),
|
||||
name => {
|
||||
self.0.attributes.push(api::KeyValue::new(name, value));
|
||||
self.0
|
||||
.attributes
|
||||
.push(KeyValue::new(name, value.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,7 +153,7 @@ impl<'a> field::Visit for SpanEventVisitor<'a> {
|
||||
/// Record events on the underlying OpenTelemetry [`Span`] from values that
|
||||
/// implement Debug.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) {
|
||||
match field.name() {
|
||||
"message" => self.0.name = format!("{:?}", value),
|
||||
@ -176,20 +163,20 @@ impl<'a> field::Visit for SpanEventVisitor<'a> {
|
||||
name => {
|
||||
self.0
|
||||
.attributes
|
||||
.push(api::KeyValue::new(name, format!("{:?}", value)));
|
||||
.push(KeyValue::new(name, format!("{:?}", value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SpanAttributeVisitor<'a>(&'a mut api::SpanBuilder);
|
||||
struct SpanAttributeVisitor<'a>(&'a mut otel::SpanBuilder);
|
||||
|
||||
impl<'a> field::Visit for SpanAttributeVisitor<'a> {
|
||||
/// Set attributes on the underlying OpenTelemetry [`Span`] from `bool` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_bool(&mut self, field: &field::Field, value: bool) {
|
||||
let attribute = api::KeyValue::new(field.name(), value);
|
||||
let attribute = KeyValue::new(field.name(), value);
|
||||
if let Some(attributes) = &mut self.0.attributes {
|
||||
attributes.push(attribute);
|
||||
} else {
|
||||
@ -199,21 +186,9 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
|
||||
|
||||
/// Set attributes on the underlying OpenTelemetry [`Span`] from `i64` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_i64(&mut self, field: &field::Field, value: i64) {
|
||||
let attribute = api::KeyValue::new(field.name(), value);
|
||||
if let Some(attributes) = &mut self.0.attributes {
|
||||
attributes.push(attribute);
|
||||
} else {
|
||||
self.0.attributes = Some(vec![attribute]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set attributes on the underlying OpenTelemetry [`Span`] from `u64` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
fn record_u64(&mut self, field: &field::Field, value: u64) {
|
||||
let attribute = api::KeyValue::new(field.name(), value);
|
||||
let attribute = KeyValue::new(field.name(), value);
|
||||
if let Some(attributes) = &mut self.0.attributes {
|
||||
attributes.push(attribute);
|
||||
} else {
|
||||
@ -223,14 +198,14 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
|
||||
|
||||
/// Set attributes on the underlying OpenTelemetry [`Span`] from `&str` values.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_str(&mut self, field: &field::Field, value: &str) {
|
||||
if field.name() == SPAN_NAME_FIELD {
|
||||
self.0.name = value.to_string();
|
||||
} else if field.name() == SPAN_KIND_FIELD {
|
||||
self.0.span_kind = str_to_span_kind(value);
|
||||
} else {
|
||||
let attribute = api::KeyValue::new(field.name(), value);
|
||||
let attribute = KeyValue::new(field.name(), value.to_string());
|
||||
if let Some(attributes) = &mut self.0.attributes {
|
||||
attributes.push(attribute);
|
||||
} else {
|
||||
@ -242,14 +217,14 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
|
||||
/// Set attributes on the underlying OpenTelemetry [`Span`] from values that
|
||||
/// implement Debug.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) {
|
||||
if field.name() == SPAN_NAME_FIELD {
|
||||
self.0.name = format!("{:?}", value);
|
||||
} else if field.name() == SPAN_KIND_FIELD {
|
||||
self.0.span_kind = str_to_span_kind(&format!("{:?}", value));
|
||||
} else {
|
||||
let attribute = api::Key::new(field.name()).string(format!("{:?}", value));
|
||||
let attribute = Key::new(field.name()).string(format!("{:?}", value));
|
||||
if let Some(attributes) = &mut self.0.attributes {
|
||||
attributes.push(attribute);
|
||||
} else {
|
||||
@ -262,42 +237,25 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
|
||||
impl<S, T> OpenTelemetryLayer<S, T>
|
||||
where
|
||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||
T: api::Tracer + PreSampledTracer + 'static,
|
||||
T: otel::Tracer + PreSampledTracer + 'static,
|
||||
{
|
||||
/// Set the [`Tracer`] that this layer will use to produce and track
|
||||
/// OpenTelemetry [`Span`]s.
|
||||
///
|
||||
/// [`Tracer`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/trait.Tracer.html
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Tracer`]: opentelemetry::trace::Tracer
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use opentelemetry::{api::Provider, sdk};
|
||||
/// ```no_run
|
||||
/// use tracing_opentelemetry::OpenTelemetryLayer;
|
||||
/// use tracing_subscriber::layer::SubscriberExt;
|
||||
/// use tracing_subscriber::Registry;
|
||||
///
|
||||
/// // Create a jaeger exporter for a `trace-demo` service.
|
||||
/// let exporter = opentelemetry_jaeger::Exporter::builder()
|
||||
/// .with_agent_endpoint("127.0.0.1:6831".parse().unwrap())
|
||||
/// .with_process(opentelemetry_jaeger::Process {
|
||||
/// service_name: "trace_demo".to_string(),
|
||||
/// tags: Vec::new(),
|
||||
/// })
|
||||
/// .init().expect("Error initializing Jaeger exporter");
|
||||
///
|
||||
/// // Build a provider from the jaeger exporter that always samples.
|
||||
/// let provider = sdk::Provider::builder()
|
||||
/// .with_simple_exporter(exporter)
|
||||
/// .with_config(sdk::Config {
|
||||
/// default_sampler: Box::new(sdk::Sampler::AlwaysOn),
|
||||
/// ..Default::default()
|
||||
/// })
|
||||
/// .build();
|
||||
///
|
||||
/// // Get a tracer from the provider for a component
|
||||
/// let tracer = provider.get_tracer("component-name");
|
||||
/// // Create a jaeger exporter pipeline for a `trace_demo` service.
|
||||
/// let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline()
|
||||
/// .with_service_name("trace_demo")
|
||||
/// .install().expect("Error initializing Jaeger exporter");
|
||||
///
|
||||
/// // Create a layer with the configured tracer
|
||||
/// let otel_layer = OpenTelemetryLayer::new(tracer);
|
||||
@ -318,49 +276,31 @@ where
|
||||
/// Set the [`Tracer`] that this layer will use to produce and track
|
||||
/// OpenTelemetry [`Span`]s.
|
||||
///
|
||||
/// [`Tracer`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/trait.Tracer.html
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Tracer`]: opentelemetry::trace::Tracer
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use opentelemetry::{api::Provider, sdk};
|
||||
/// ```no_run
|
||||
/// use tracing_subscriber::layer::SubscriberExt;
|
||||
/// use tracing_subscriber::Registry;
|
||||
///
|
||||
/// // Create a jaeger exporter for a `trace-demo` service.
|
||||
/// let exporter = opentelemetry_jaeger::Exporter::builder()
|
||||
/// .with_agent_endpoint("127.0.0.1:6831".parse().unwrap())
|
||||
/// .with_process(opentelemetry_jaeger::Process {
|
||||
/// service_name: "trace_demo".to_string(),
|
||||
/// tags: Vec::new(),
|
||||
/// })
|
||||
/// .init().expect("Error initializing Jaeger exporter");
|
||||
///
|
||||
/// // Build a provider from the jaeger exporter that always samples.
|
||||
/// let provider = sdk::Provider::builder()
|
||||
/// .with_simple_exporter(exporter)
|
||||
/// .with_config(sdk::Config {
|
||||
/// default_sampler: Box::new(sdk::Sampler::AlwaysOn),
|
||||
/// ..Default::default()
|
||||
/// })
|
||||
/// .build();
|
||||
///
|
||||
/// // Get a tracer from the provider for a component
|
||||
/// let tracer = provider.get_tracer("component-name");
|
||||
/// // Create a jaeger exporter pipeline for a `trace_demo` service.
|
||||
/// let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline()
|
||||
/// .with_service_name("trace_demo")
|
||||
/// .install().expect("Error initializing Jaeger exporter");
|
||||
///
|
||||
/// // Create a layer with the configured tracer
|
||||
/// let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
///
|
||||
/// // Use the tracing subscriber `Registry`, or any other subscriber
|
||||
/// // that impls `LookupSpan`
|
||||
/// let subscriber = Registry::default()
|
||||
/// .with(otel_layer);
|
||||
/// let subscriber = Registry::default().with(otel_layer);
|
||||
/// # drop(subscriber);
|
||||
/// ```
|
||||
pub fn with_tracer<Tracer>(self, tracer: Tracer) -> OpenTelemetryLayer<S, Tracer>
|
||||
where
|
||||
Tracer: api::Tracer + PreSampledTracer + 'static,
|
||||
Tracer: otel::Tracer + PreSampledTracer + 'static,
|
||||
{
|
||||
OpenTelemetryLayer {
|
||||
tracer,
|
||||
@ -373,27 +313,27 @@ where
|
||||
/// tracing [`span`] through the [`Registry`]. This [`SpanContext`]
|
||||
/// links spans to their parent for proper hierarchical visualization.
|
||||
///
|
||||
/// [`SpanContext`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span_context/struct.SpanContext.html
|
||||
/// [`span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html
|
||||
/// [`Registry`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.Registry.html
|
||||
/// [`SpanContext`]: opentelemetry::trace::SpanContext
|
||||
/// [`span`]: tracing::Span
|
||||
/// [`Registry`]: tracing_subscriber::Registry
|
||||
fn parent_span_context(
|
||||
&self,
|
||||
attrs: &Attributes<'_>,
|
||||
ctx: &Context<'_, S>,
|
||||
) -> Option<api::SpanContext> {
|
||||
) -> Option<otel::SpanContext> {
|
||||
// If a span is specified, it _should_ exist in the underlying `Registry`.
|
||||
if let Some(parent) = attrs.parent() {
|
||||
let span = ctx.span(parent).expect("Span not found, this is a bug");
|
||||
let mut extensions = span.extensions_mut();
|
||||
extensions
|
||||
.get_mut::<api::SpanBuilder>()
|
||||
.get_mut::<otel::SpanBuilder>()
|
||||
.map(|builder| self.tracer.sampled_span_context(builder))
|
||||
// Else if the span is inferred from context, look up any available current span.
|
||||
} else if attrs.is_contextual() {
|
||||
ctx.lookup_current().and_then(|span| {
|
||||
let mut extensions = span.extensions_mut();
|
||||
extensions
|
||||
.get_mut::<api::SpanBuilder>()
|
||||
.get_mut::<otel::SpanBuilder>()
|
||||
.map(|builder| self.tracer.sampled_span_context(builder))
|
||||
})
|
||||
// Explicit root spans should have no parent context.
|
||||
@ -405,7 +345,7 @@ where
|
||||
fn get_context(
|
||||
dispatch: &tracing::Dispatch,
|
||||
id: &span::Id,
|
||||
f: &mut dyn FnMut(&mut api::SpanBuilder, &dyn PreSampledTracer),
|
||||
f: &mut dyn FnMut(&mut otel::SpanBuilder, &dyn PreSampledTracer),
|
||||
) {
|
||||
let subscriber = dispatch
|
||||
.downcast_ref::<S>()
|
||||
@ -418,7 +358,7 @@ where
|
||||
.expect("layer should downcast to expected type; this is a bug!");
|
||||
|
||||
let mut extensions = span.extensions_mut();
|
||||
if let Some(builder) = extensions.get_mut::<api::SpanBuilder>() {
|
||||
if let Some(builder) = extensions.get_mut::<otel::SpanBuilder>() {
|
||||
f(builder, &layer.tracer);
|
||||
}
|
||||
}
|
||||
@ -427,12 +367,12 @@ where
|
||||
impl<S, T> Layer<S> for OpenTelemetryLayer<S, T>
|
||||
where
|
||||
S: Subscriber + for<'span> LookupSpan<'span>,
|
||||
T: api::Tracer + PreSampledTracer + 'static,
|
||||
T: otel::Tracer + PreSampledTracer + 'static,
|
||||
{
|
||||
/// Creates an [OpenTelemetry `Span`] for the corresponding [tracing `Span`].
|
||||
///
|
||||
/// [OpenTelemetry `Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [tracing `Span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html
|
||||
/// [OpenTelemetry `Span`]: opentelemetry::trace::Span
|
||||
/// [tracing `Span`]: tracing::Span
|
||||
fn new_span(&self, attrs: &Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
|
||||
let span = ctx.span(id).expect("Span not found, this is a bug");
|
||||
let mut extensions = span.extensions_mut();
|
||||
@ -449,7 +389,8 @@ where
|
||||
|
||||
// Ensure trace id exists so children are matched properly.
|
||||
if builder.parent_context.is_none() {
|
||||
let existing_otel_span_context = OtelContext::current().span().span_context();
|
||||
let cx = OtelContext::current();
|
||||
let existing_otel_span_context = cx.span().span_context();
|
||||
if existing_otel_span_context.is_valid() {
|
||||
builder.trace_id = Some(existing_otel_span_context.trace_id());
|
||||
} else {
|
||||
@ -463,11 +404,11 @@ where
|
||||
|
||||
/// Record OpenTelemetry [`attributes`] for the given values.
|
||||
///
|
||||
/// [`attributes`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/struct.SpanBuilder.html#structfield.attributes
|
||||
/// [`attributes`]: opentelemetry::trace::SpanBuilder::attributes
|
||||
fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
|
||||
let span = ctx.span(id).expect("Span not found, this is a bug");
|
||||
let mut extensions = span.extensions_mut();
|
||||
if let Some(builder) = extensions.get_mut::<api::SpanBuilder>() {
|
||||
if let Some(builder) = extensions.get_mut::<otel::SpanBuilder>() {
|
||||
values.record(&mut SpanAttributeVisitor(builder));
|
||||
}
|
||||
}
|
||||
@ -476,7 +417,7 @@ where
|
||||
let span = ctx.span(id).expect("Span not found, this is a bug");
|
||||
let mut extensions = span.extensions_mut();
|
||||
let builder = extensions
|
||||
.get_mut::<api::SpanBuilder>()
|
||||
.get_mut::<otel::SpanBuilder>()
|
||||
.expect("Missing SpanBuilder span extensions");
|
||||
|
||||
let follows_span = ctx
|
||||
@ -484,11 +425,11 @@ where
|
||||
.expect("Span to follow not found, this is a bug");
|
||||
let mut follows_extensions = follows_span.extensions_mut();
|
||||
let follows_builder = follows_extensions
|
||||
.get_mut::<api::SpanBuilder>()
|
||||
.get_mut::<otel::SpanBuilder>()
|
||||
.expect("Missing SpanBuilder span extensions");
|
||||
|
||||
let follows_context = self.tracer.sampled_span_context(follows_builder);
|
||||
let follows_link = api::Link::new(follows_context, Vec::new());
|
||||
let follows_link = otel::Link::new(follows_context, Vec::new());
|
||||
if let Some(ref mut links) = builder.links {
|
||||
links.push(follows_link);
|
||||
} else {
|
||||
@ -499,11 +440,11 @@ where
|
||||
/// Records OpenTelemetry [`Event`] data on event.
|
||||
///
|
||||
/// Note: an [`ERROR`]-level event will also set the OpenTelemetry span status code to
|
||||
/// [`Unknown`], signaling that an error has occurred.
|
||||
/// [`Error`], signaling that an error has occurred.
|
||||
///
|
||||
/// [`Event`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/event/struct.Event.html
|
||||
/// [`ERROR`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.ERROR
|
||||
/// [`Unknown`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/enum.StatusCode.html#variant.Unknown
|
||||
/// [`Event`]: opentelemetry::trace::Event
|
||||
/// [`ERROR`]: tracing::Level::ERROR
|
||||
/// [`Error`]: opentelemetry::trace::StatusCode::Error
|
||||
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
|
||||
// Ignore events that are not in the context of a span
|
||||
if let Some(span) = ctx.lookup_current() {
|
||||
@ -515,20 +456,20 @@ where
|
||||
let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
|
||||
#[cfg(not(feature = "tracing-log"))]
|
||||
let meta = event.metadata();
|
||||
let mut otel_event = api::Event::new(
|
||||
let mut otel_event = otel::Event::new(
|
||||
String::new(),
|
||||
SystemTime::now(),
|
||||
vec![
|
||||
api::Key::new("level").string(meta.level().to_string()),
|
||||
api::Key::new("target").string(meta.target()),
|
||||
Key::new("level").string(meta.level().to_string()),
|
||||
Key::new("target").string(meta.target().to_string()),
|
||||
],
|
||||
);
|
||||
event.record(&mut SpanEventVisitor(&mut otel_event));
|
||||
|
||||
let mut extensions = span.extensions_mut();
|
||||
if let Some(builder) = extensions.get_mut::<api::SpanBuilder>() {
|
||||
if let Some(builder) = extensions.get_mut::<otel::SpanBuilder>() {
|
||||
if builder.status_code.is_none() && *meta.level() == tracing_core::Level::ERROR {
|
||||
builder.status_code = Some(api::StatusCode::Unknown);
|
||||
builder.status_code = Some(otel::StatusCode::Error);
|
||||
}
|
||||
|
||||
if let Some(ref mut events) = builder.message_events {
|
||||
@ -542,11 +483,11 @@ where
|
||||
|
||||
/// Exports an OpenTelemetry [`Span`] on close.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html
|
||||
/// [`Span`]: opentelemetry::trace::Span
|
||||
fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
|
||||
let span = ctx.span(&id).expect("Span not found, this is a bug");
|
||||
let mut extensions = span.extensions_mut();
|
||||
if let Some(builder) = extensions.remove::<api::SpanBuilder>() {
|
||||
if let Some(builder) = extensions.remove::<otel::SpanBuilder>() {
|
||||
// Assign end time, build and start span, drop span to export
|
||||
builder.with_end_time(SystemTime::now()).start(&self.tracer);
|
||||
}
|
||||
@ -568,57 +509,55 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use opentelemetry::api;
|
||||
use opentelemetry::api::TraceContextExt;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::SystemTime;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct TestTracer(Arc<Mutex<Option<api::SpanBuilder>>>);
|
||||
impl api::Tracer for TestTracer {
|
||||
type Span = api::NoopSpan;
|
||||
struct TestTracer(Arc<Mutex<Option<otel::SpanBuilder>>>);
|
||||
impl otel::Tracer for TestTracer {
|
||||
type Span = otel::NoopSpan;
|
||||
fn invalid(&self) -> Self::Span {
|
||||
api::NoopSpan::new()
|
||||
otel::NoopSpan::new()
|
||||
}
|
||||
fn start_from_context(&self, _name: &str, _context: &api::Context) -> Self::Span {
|
||||
fn start_from_context(&self, _name: &str, _context: &OtelContext) -> Self::Span {
|
||||
self.invalid()
|
||||
}
|
||||
fn span_builder(&self, name: &str) -> api::SpanBuilder {
|
||||
api::SpanBuilder::from_name(name.to_string())
|
||||
fn span_builder(&self, name: &str) -> otel::SpanBuilder {
|
||||
otel::SpanBuilder::from_name(name.to_string())
|
||||
}
|
||||
fn build_with_context(&self, builder: api::SpanBuilder, _cx: &api::Context) -> Self::Span {
|
||||
fn build_with_context(&self, builder: otel::SpanBuilder, _cx: &OtelContext) -> Self::Span {
|
||||
*self.0.lock().unwrap() = Some(builder);
|
||||
self.invalid()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreSampledTracer for TestTracer {
|
||||
fn sampled_span_context(&self, _builder: &mut api::SpanBuilder) -> api::SpanContext {
|
||||
api::SpanContext::empty_context()
|
||||
fn sampled_span_context(&self, _builder: &mut otel::SpanBuilder) -> otel::SpanContext {
|
||||
otel::SpanContext::empty_context()
|
||||
}
|
||||
fn new_trace_id(&self) -> api::TraceId {
|
||||
api::TraceId::invalid()
|
||||
fn new_trace_id(&self) -> otel::TraceId {
|
||||
otel::TraceId::invalid()
|
||||
}
|
||||
fn new_span_id(&self) -> api::SpanId {
|
||||
api::SpanId::invalid()
|
||||
fn new_span_id(&self) -> otel::SpanId {
|
||||
otel::SpanId::invalid()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct TestSpan(api::SpanContext);
|
||||
impl api::Span for TestSpan {
|
||||
fn add_event_with_timestamp(&self, _: String, _: SystemTime, _: Vec<api::KeyValue>) {}
|
||||
fn span_context(&self) -> api::SpanContext {
|
||||
self.0.clone()
|
||||
struct TestSpan(otel::SpanContext);
|
||||
impl otel::Span for TestSpan {
|
||||
fn add_event_with_timestamp(&self, _: String, _: SystemTime, _: Vec<KeyValue>) {}
|
||||
fn span_context(&self) -> &otel::SpanContext {
|
||||
&self.0
|
||||
}
|
||||
fn is_recording(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn set_attribute(&self, _attribute: api::KeyValue) {}
|
||||
fn set_status(&self, _code: api::StatusCode, _message: String) {}
|
||||
fn set_attribute(&self, _attribute: KeyValue) {}
|
||||
fn set_status(&self, _code: otel::StatusCode, _message: String) {}
|
||||
fn update_name(&self, _new_name: String) {}
|
||||
fn end(&self) {}
|
||||
fn end_with_timestamp(&self, _timestamp: SystemTime) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -645,19 +584,20 @@ mod tests {
|
||||
});
|
||||
|
||||
let recorded_kind = tracer.0.lock().unwrap().as_ref().unwrap().span_kind.clone();
|
||||
assert_eq!(recorded_kind, Some(api::SpanKind::Server))
|
||||
assert_eq!(recorded_kind, Some(otel::SpanKind::Server))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_id_from_existing_context() {
|
||||
let tracer = TestTracer(Arc::new(Mutex::new(None)));
|
||||
let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone()));
|
||||
let trace_id = api::TraceId::from_u128(42);
|
||||
let existing_cx = api::Context::current_with_span(TestSpan(api::SpanContext::new(
|
||||
let trace_id = otel::TraceId::from_u128(42);
|
||||
let existing_cx = OtelContext::current_with_span(TestSpan(otel::SpanContext::new(
|
||||
trace_id,
|
||||
api::SpanId::from_u64(1),
|
||||
otel::SpanId::from_u64(1),
|
||||
0,
|
||||
false,
|
||||
Default::default(),
|
||||
)));
|
||||
let _g = existing_cx.attach();
|
||||
|
||||
|
@ -43,25 +43,27 @@
|
||||
//! ### Stability Status
|
||||
//!
|
||||
//! The OpenTelemetry specification is currently in beta so some breaking
|
||||
//! may still occur on the path to 1.0. You can follow the changes via the
|
||||
//! [spec repository] to track progress toward stabilization.
|
||||
//! changes may still occur on the path to 1.0. You can follow the changes via
|
||||
//! the [spec repository] to track progress toward stabilization.
|
||||
//!
|
||||
//! [spec repository]: https://github.com/open-telemetry/opentelemetry-specification
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! ```
|
||||
//! use opentelemetry::{api::Provider, sdk};
|
||||
//! use opentelemetry::exporter::trace::stdout;
|
||||
//! use tracing::{error, span};
|
||||
//! use tracing_subscriber::layer::SubscriberExt;
|
||||
//! use tracing_subscriber::Registry;
|
||||
//!
|
||||
//! // Create a new tracer
|
||||
//! let tracer = sdk::Provider::default().get_tracer("service_name");
|
||||
//! // Create a new OpenTelemetry pipeline
|
||||
//! let (tracer, _uninstall) = stdout::new_pipeline().install();
|
||||
//!
|
||||
//! // Create a new OpenTelemetry tracing layer
|
||||
//! // Create a tracing layer with the configured tracer
|
||||
//! let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
//!
|
||||
//! // Use the tracing subscriber `Registry`, or any other subscriber
|
||||
//! // that impls `LookupSpan`
|
||||
//! let subscriber = Registry::default().with(telemetry);
|
||||
//!
|
||||
//! // Trace executed code
|
||||
|
@ -1,32 +1,33 @@
|
||||
use crate::layer::WithContext;
|
||||
use opentelemetry::api;
|
||||
use opentelemetry::api::TraceContextExt;
|
||||
use opentelemetry::{trace as otel, trace::TraceContextExt, Context, KeyValue};
|
||||
use std::time::SystemTime;
|
||||
|
||||
/// Utility functions to allow tracing [`Span`]s to accept and return
|
||||
/// [OpenTelemetry] [`Context`]s.
|
||||
///
|
||||
/// [`Span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html
|
||||
/// [OpenTelemetry]: https://opentelemetry.io
|
||||
/// [`Context`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/struct.Context.html
|
||||
/// [`Context`]: opentelemetry::Context
|
||||
pub trait OpenTelemetrySpanExt {
|
||||
/// Associates `self` with a given OpenTelemetry trace, using the provided
|
||||
/// parent [`Context`].
|
||||
///
|
||||
/// [`Context`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/struct.Context.html
|
||||
/// [`Context`]: opentelemetry::Context
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use opentelemetry::api::{self, HttpTextFormat, TraceContextExt};
|
||||
/// use opentelemetry::{propagation::TextMapPropagator, trace::TraceContextExt};
|
||||
/// use opentelemetry::sdk::propagation::B3Propagator;
|
||||
/// use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
/// use std::collections::HashMap;
|
||||
/// use tracing::Span;
|
||||
///
|
||||
/// // Example carrier, could be a framework header map that impls `api::Carrier`.
|
||||
/// // Example carrier, could be a framework header map that impls otel's `Extract`.
|
||||
/// let mut carrier = HashMap::new();
|
||||
///
|
||||
/// // Propagator can be swapped with trace context propagator binary propagator, etc.
|
||||
/// let propagator = api::B3Propagator::new();
|
||||
/// // Propagator can be swapped with trace context propagator, binary propagator, etc.
|
||||
/// let propagator = B3Propagator::new();
|
||||
///
|
||||
/// // Extract otel parent context via the chosen propagator
|
||||
/// let parent_context = propagator.extract(&carrier);
|
||||
@ -40,22 +41,22 @@ pub trait OpenTelemetrySpanExt {
|
||||
/// // Or if the current span has been created elsewhere:
|
||||
/// Span::current().set_parent(&parent_context);
|
||||
/// ```
|
||||
fn set_parent(&self, span_context: &api::Context);
|
||||
fn set_parent(&self, cx: &Context);
|
||||
|
||||
/// Extracts an OpenTelemetry [`Context`] from `self`.
|
||||
///
|
||||
/// [`Context`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/struct.Context.html
|
||||
/// [`Context`]: opentelemetry::Context
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use opentelemetry::api;
|
||||
/// use opentelemetry::Context;
|
||||
/// use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
/// use tracing::Span;
|
||||
///
|
||||
/// fn make_request(cx: api::Context) {
|
||||
/// fn make_request(cx: Context) {
|
||||
/// // perform external request after injecting context
|
||||
/// // e.g. if there are request headers that impl `opentelemetry::api::Carrier`
|
||||
/// // e.g. if the request's headers impl `opentelemetry::propagation::Injector`
|
||||
/// // then `propagator.inject_context(cx, request.headers_mut())`
|
||||
/// }
|
||||
///
|
||||
@ -69,21 +70,21 @@ pub trait OpenTelemetrySpanExt {
|
||||
/// // Or if the current span has been created elsewhere:
|
||||
/// make_request(Span::current().context())
|
||||
/// ```
|
||||
fn context(&self) -> api::Context;
|
||||
fn context(&self) -> Context;
|
||||
}
|
||||
|
||||
impl OpenTelemetrySpanExt for tracing::Span {
|
||||
fn set_parent(&self, parent_context: &api::Context) {
|
||||
fn set_parent(&self, cx: &Context) {
|
||||
self.with_subscriber(move |(id, subscriber)| {
|
||||
if let Some(get_context) = subscriber.downcast_ref::<WithContext>() {
|
||||
get_context.with_context(subscriber, id, move |builder, _tracer| {
|
||||
builder.parent_context = parent_context.remote_span_context().cloned()
|
||||
builder.parent_context = cx.remote_span_context().cloned()
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn context(&self) -> api::Context {
|
||||
fn context(&self) -> Context {
|
||||
let mut span_context = None;
|
||||
self.with_subscriber(|(id, subscriber)| {
|
||||
if let Some(get_context) = subscriber.downcast_ref::<WithContext>() {
|
||||
@ -93,20 +94,21 @@ impl OpenTelemetrySpanExt for tracing::Span {
|
||||
}
|
||||
});
|
||||
|
||||
let compat_span = CompatSpan(span_context.unwrap_or_else(api::SpanContext::empty_context));
|
||||
api::Context::current_with_span(compat_span)
|
||||
let span_context = span_context.unwrap_or_else(otel::SpanContext::empty_context);
|
||||
let compat_span = CompatSpan(span_context);
|
||||
Context::current_with_span(compat_span)
|
||||
}
|
||||
}
|
||||
|
||||
/// A compatibility wrapper for an injectable OpenTelemetry span context.
|
||||
#[derive(Debug)]
|
||||
struct CompatSpan(api::SpanContext);
|
||||
impl api::Span for CompatSpan {
|
||||
struct CompatSpan(otel::SpanContext);
|
||||
impl otel::Span for CompatSpan {
|
||||
fn add_event_with_timestamp(
|
||||
&self,
|
||||
_name: String,
|
||||
_timestamp: std::time::SystemTime,
|
||||
_attributes: Vec<api::KeyValue>,
|
||||
_attributes: Vec<KeyValue>,
|
||||
) {
|
||||
#[cfg(debug_assertions)]
|
||||
panic!(
|
||||
@ -115,11 +117,11 @@ impl api::Span for CompatSpan {
|
||||
}
|
||||
|
||||
/// This method is used by OpenTelemetry propagators to inject span context
|
||||
/// information into [`Carrier`]s.
|
||||
/// information into [`Injector`]s.
|
||||
///
|
||||
/// [`Carrier`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/propagation/trait.Carrier.html
|
||||
fn span_context(&self) -> api::SpanContext {
|
||||
self.0.clone()
|
||||
/// [`Injector`]: opentelemetry::propagation::Injector
|
||||
fn span_context(&self) -> &otel::SpanContext {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn is_recording(&self) -> bool {
|
||||
@ -130,12 +132,12 @@ impl api::Span for CompatSpan {
|
||||
false
|
||||
}
|
||||
|
||||
fn set_attribute(&self, _attribute: api::KeyValue) {
|
||||
fn set_attribute(&self, _attribute: KeyValue) {
|
||||
#[cfg(debug_assertions)]
|
||||
panic!("OpenTelemetry and tracing APIs cannot be mixed, use `tracing::span!` macro or `span.record()` instead.");
|
||||
}
|
||||
|
||||
fn set_status(&self, _code: api::StatusCode, _message: String) {
|
||||
fn set_status(&self, _code: otel::StatusCode, _message: String) {
|
||||
#[cfg(debug_assertions)]
|
||||
panic!("OpenTelemetry and tracing APIs cannot be mixed, use `tracing::span!` macro or `span.record()` instead.");
|
||||
}
|
||||
@ -145,7 +147,7 @@ impl api::Span for CompatSpan {
|
||||
panic!("OpenTelemetry and tracing APIs cannot be mixed, span names are not mutable.");
|
||||
}
|
||||
|
||||
fn end(&self) {
|
||||
fn end_with_timestamp(&self, _timestamp: SystemTime) {
|
||||
#[cfg(debug_assertions)]
|
||||
panic!("OpenTelemetry and tracing APIs cannot be mixed, span end times are set when the underlying tracing span closes.");
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use opentelemetry::{api, sdk};
|
||||
use opentelemetry::sdk::trace::{SamplingDecision, Tracer};
|
||||
use opentelemetry::trace as otel;
|
||||
|
||||
/// An interface for authors of OpenTelemetry SDKs to build pre-sampled tracers.
|
||||
///
|
||||
@ -20,67 +21,71 @@ use opentelemetry::{api, sdk};
|
||||
/// See the [`OpenTelemetrySpanExt::set_parent`] and
|
||||
/// [`OpenTelemetrySpanExt::context`] methods for example usage.
|
||||
///
|
||||
/// [`Tracer`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/trait.Tracer.html
|
||||
/// [`SpanBuilder`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/struct.SpanBuilder.html
|
||||
/// [`SpanContext`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span_context/struct.SpanContext.html
|
||||
/// [`PreSampledTracer::sampled_span_context`]: trait.PreSampledTracer.html#tymethod.sampled_span_context
|
||||
/// [`OpenTelemetrySpanExt::set_parent`]: trait.OpenTelemetrySpanExt.html#tymethod.set_parent
|
||||
/// [`OpenTelemetrySpanExt::context`]: trait.OpenTelemetrySpanExt.html#tymethod.context
|
||||
/// [`Tracer`]: opentelemetry::trace::Tracer
|
||||
/// [`SpanBuilder`]: opentelemetry::trace::SpanBuilder
|
||||
/// [`SpanContext`]: opentelemetry::trace::SpanContext
|
||||
/// [`PreSampledTracer::sampled_span_context`]: crate::PreSampledTracer::sampled_span_context
|
||||
/// [`OpenTelemetrySpanExt::set_parent`]: crate::OpenTelemetrySpanExt::set_parent
|
||||
/// [`OpenTelemetrySpanExt::context`]: crate::OpenTelemetrySpanExt::context
|
||||
pub trait PreSampledTracer {
|
||||
/// Produce a pre-sampled span context for the given span builder.
|
||||
fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext;
|
||||
fn sampled_span_context(&self, builder: &mut otel::SpanBuilder) -> otel::SpanContext;
|
||||
|
||||
/// Generate a new trace id.
|
||||
fn new_trace_id(&self) -> api::TraceId;
|
||||
fn new_trace_id(&self) -> otel::TraceId;
|
||||
|
||||
/// Generate a new span id.
|
||||
fn new_span_id(&self) -> api::SpanId;
|
||||
fn new_span_id(&self) -> otel::SpanId;
|
||||
}
|
||||
|
||||
impl PreSampledTracer for api::NoopTracer {
|
||||
fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext {
|
||||
impl PreSampledTracer for otel::NoopTracer {
|
||||
fn sampled_span_context(&self, builder: &mut otel::SpanBuilder) -> otel::SpanContext {
|
||||
builder
|
||||
.parent_context
|
||||
.clone()
|
||||
.unwrap_or_else(api::SpanContext::empty_context)
|
||||
.unwrap_or_else(otel::SpanContext::empty_context)
|
||||
}
|
||||
|
||||
fn new_trace_id(&self) -> api::TraceId {
|
||||
api::TraceId::invalid()
|
||||
fn new_trace_id(&self) -> otel::TraceId {
|
||||
otel::TraceId::invalid()
|
||||
}
|
||||
|
||||
fn new_span_id(&self) -> api::SpanId {
|
||||
api::SpanId::invalid()
|
||||
fn new_span_id(&self) -> otel::SpanId {
|
||||
otel::SpanId::invalid()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreSampledTracer for sdk::Tracer {
|
||||
fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext {
|
||||
let span_id = builder
|
||||
.span_id
|
||||
.unwrap_or_else(|| self.provider().config().id_generator.new_span_id());
|
||||
impl PreSampledTracer for Tracer {
|
||||
fn sampled_span_context(&self, builder: &mut otel::SpanBuilder) -> otel::SpanContext {
|
||||
let span_id = builder.span_id.unwrap_or_else(|| {
|
||||
self.provider()
|
||||
.map(|provider| provider.config().id_generator.new_span_id())
|
||||
.unwrap_or_else(otel::SpanId::invalid)
|
||||
});
|
||||
let (trace_id, trace_flags) = builder
|
||||
.parent_context
|
||||
.as_ref()
|
||||
.filter(|parent_context| parent_context.is_valid())
|
||||
.map(|parent_context| (parent_context.trace_id(), parent_context.trace_flags()))
|
||||
.unwrap_or_else(|| {
|
||||
let trace_id = builder
|
||||
.trace_id
|
||||
.unwrap_or_else(|| self.provider().config().id_generator.new_trace_id());
|
||||
let trace_id = builder.trace_id.unwrap_or_else(|| {
|
||||
self.provider()
|
||||
.map(|provider| provider.config().id_generator.new_trace_id())
|
||||
.unwrap_or_else(otel::TraceId::invalid)
|
||||
});
|
||||
|
||||
// ensure sampling decision is recorded so all span contexts have consistent flags
|
||||
let sampling_decision = if let Some(result) = builder.sampling_result.as_ref() {
|
||||
result.decision.clone()
|
||||
} else {
|
||||
let mut result = self.provider().config().default_sampler.should_sample(
|
||||
} else if let Some(provider) = self.provider().as_ref() {
|
||||
let mut result = provider.config().default_sampler.should_sample(
|
||||
builder.parent_context.as_ref(),
|
||||
trace_id,
|
||||
&builder.name,
|
||||
builder
|
||||
.span_kind
|
||||
.as_ref()
|
||||
.unwrap_or(&api::SpanKind::Internal),
|
||||
.unwrap_or(&otel::SpanKind::Internal),
|
||||
builder.attributes.as_ref().unwrap_or(&Vec::new()),
|
||||
builder.links.as_ref().unwrap_or(&Vec::new()),
|
||||
);
|
||||
@ -93,10 +98,12 @@ impl PreSampledTracer for sdk::Tracer {
|
||||
}
|
||||
|
||||
result.decision
|
||||
} else {
|
||||
SamplingDecision::Drop
|
||||
};
|
||||
|
||||
let trace_flags = if sampling_decision == sdk::SamplingDecision::RecordAndSampled {
|
||||
api::TRACE_FLAG_SAMPLED
|
||||
let trace_flags = if sampling_decision == SamplingDecision::RecordAndSample {
|
||||
otel::TRACE_FLAG_SAMPLED
|
||||
} else {
|
||||
0
|
||||
};
|
||||
@ -104,27 +111,32 @@ impl PreSampledTracer for sdk::Tracer {
|
||||
(trace_id, trace_flags)
|
||||
});
|
||||
|
||||
api::SpanContext::new(trace_id, span_id, trace_flags, false)
|
||||
otel::SpanContext::new(trace_id, span_id, trace_flags, false, Default::default())
|
||||
}
|
||||
|
||||
fn new_trace_id(&self) -> api::TraceId {
|
||||
self.provider().config().id_generator.new_trace_id()
|
||||
fn new_trace_id(&self) -> otel::TraceId {
|
||||
self.provider()
|
||||
.map(|provider| provider.config().id_generator.new_trace_id())
|
||||
.unwrap_or_else(otel::TraceId::invalid)
|
||||
}
|
||||
|
||||
fn new_span_id(&self) -> api::SpanId {
|
||||
self.provider().config().id_generator.new_span_id()
|
||||
fn new_span_id(&self) -> otel::SpanId {
|
||||
self.provider()
|
||||
.map(|provider| provider.config().id_generator.new_span_id())
|
||||
.unwrap_or_else(otel::SpanId::invalid)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use opentelemetry::api::{Provider, SpanBuilder};
|
||||
use opentelemetry::sdk;
|
||||
use opentelemetry::trace::{SpanBuilder, TracerProvider};
|
||||
|
||||
#[test]
|
||||
fn assigns_default_ids_if_missing() {
|
||||
let tracer = sdk::Provider::default().get_tracer("test");
|
||||
let provider = sdk::trace::TracerProvider::default();
|
||||
let tracer = provider.get_tracer("test", None);
|
||||
let mut builder = SpanBuilder::from_name("empty".to_string());
|
||||
builder.trace_id = None;
|
||||
builder.span_id = None;
|
||||
|
Loading…
x
Reference in New Issue
Block a user