Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions examples/env-var-propagation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "env-var-propagation"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
rust-version = "1.75.0"
publish = false
autobenches = false

[[bin]]
name = "env-var-propagation"
path = "src/main.rs"
doc = false
bench = false

[dependencies]
opentelemetry = { workspace = true, features = ["trace", "otel_unstable"] }
opentelemetry_sdk = { workspace = true, features = ["trace"] }
opentelemetry-stdout = { workspace = true, features = ["trace"] }
34 changes: 34 additions & 0 deletions examples/env-var-propagation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Environment Variable Propagation Example

This example demonstrates distributed tracing across a parent process and a
child process using environment variables as the propagation carrier.

## What This Example Does

1. The parent process configures the W3C `TraceContextPropagator` and starts a
root span.
2. The parent injects that span context into an `EnvVarInjector`, then passes
the resulting environment variables to a child process.
3. The child process captures its startup environment with `EnvVarExtractor`,
extracts the propagated context, and starts its own span as a child of the
parent's span.

The example prints the parent's `TraceId` and `SpanId`, then prints the child's
`TraceId` and remote parent `SpanId` so you can see that the trace was
propagated across the process boundary.

## Usage

From `examples/env-var-propagation`, run:

```shell
cargo run
```

The output should show:

- the parent and child spans sharing the same `TraceId`
- the child's reported `parent_span_id` matching the parent's `span_id`

Both processes also export their spans to stdout using the OpenTelemetry stdout
exporter.
84 changes: 84 additions & 0 deletions examples/env-var-propagation/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use opentelemetry::{
global,
propagation::{EnvVarExtractor, EnvVarInjector},
trace::{Span, TraceContextExt, Tracer},
Context,
};
use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::SdkTracerProvider};
use opentelemetry_stdout::SpanExporter;
use std::{env, error::Error, io, process::Command};

fn init_tracer() -> SdkTracerProvider {
global::set_text_map_propagator(TraceContextPropagator::new());

let provider = SdkTracerProvider::builder()
.with_simple_exporter(SpanExporter::default())
.build();
global::set_tracer_provider(provider.clone());

provider
}

fn run_parent() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let tracer = global::tracer("examples/env-var-propagation/parent");
let span = tracer.start("parent");
let span_context = span.span_context().clone();
let cx = Context::current_with_span(span);

println!(
"parent trace_id={} span_id={}",
span_context.trace_id(),
span_context.span_id()
);

let mut child_env = EnvVarInjector::new();
global::get_text_map_propagator(|propagator| propagator.inject_context(&cx, &mut child_env));

let status = Command::new(env::current_exe()?)
.arg("--child")
.envs(child_env.into_inner())
.status()?;

cx.span().end();

if status.success() {
Ok(())
} else {
Err(io::Error::other(format!("child process failed with status {status}")).into())
}
}

fn run_child() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let extractor = EnvVarExtractor::from_env();
let parent_cx = global::get_text_map_propagator(|propagator| propagator.extract(&extractor));
let remote_parent = parent_cx.span().span_context().clone();

if !remote_parent.is_valid() {
return Err(io::Error::other("missing propagated span context").into());
}

let tracer = global::tracer("examples/env-var-propagation/child");
let mut span = tracer.start_with_context("child", &parent_cx);
let span_context = span.span_context().clone();

println!(
"child trace_id={} parent_span_id={}",
span_context.trace_id(),
remote_parent.span_id()
);

span.end();

Ok(())
}

fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let provider = init_tracer();
let result = match env::args().nth(1).as_deref() {
Some("--child") => run_child(),
_ => run_parent(),
};

provider.shutdown()?;
result
}
3 changes: 3 additions & 0 deletions opentelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## vNext

- **Added** experimental `EnvVarExtractor` and `EnvVarInjector` helpers for
propagating OpenTelemetry context through environment variables. This API is
gated behind the `otel_unstable` feature flag.
- `otel_info!`, `otel_warn!`, `otel_debug!`, and `otel_error!` macros now accept quoted-key fields
(e.g. `"otel.component.type" = "value"`) for dotted attribute names.
- **Added** `BoundGauge<T>` and `BoundUpDownCounter<T>` types (and the
Expand Down
2 changes: 2 additions & 0 deletions opentelemetry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ metrics = []
testing = ["trace"]
logs = []
internal-logs = ["tracing"]
otel_unstable = []
experimental_metrics_bound_instruments = ["metrics"]

[dev-dependencies]
opentelemetry_sdk = { path = "../opentelemetry-sdk"} # for documentation tests
criterion = { workspace = true }
rand = { workspace = true, features = ["os_rng", "thread_rng"] }
temp-env = { workspace = true }
tokio = { version = "1.0", features = ["full"] }

[[bench]]
Expand Down
7 changes: 7 additions & 0 deletions opentelemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ additional exporters and other related components as well.

See [docs](https://docs.rs/opentelemetry).

Experimental environment-variable propagation helpers are available behind the
`otel_unstable` feature flag via
`opentelemetry::propagation::EnvVarExtractor` and
`opentelemetry::propagation::EnvVarInjector`. See
[`examples/env-var-propagation`](https://github.com/open-telemetry/opentelemetry-rust/tree/main/examples/env-var-propagation)
for an end-to-end parent/child process example using `TraceContextPropagator`.

## Release Notes

You can find the release notes (changelog) [here](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry/CHANGELOG.md).
Expand Down
8 changes: 6 additions & 2 deletions opentelemetry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
//! which demonstrates creating spans and propagating trace context across a
//! gRPC client and server. See the
//! [examples](https://github.com/open-telemetry/opentelemetry-rust/tree/main/examples)
//! directory for additional integration patterns.
//! directory for additional integration patterns, including
//! [`examples/env-var-propagation`](https://github.com/open-telemetry/opentelemetry-rust/tree/main/examples/env-var-propagation)
//! for parent/child process propagation via environment variables.
//!
//! See the [`trace`] module docs for more information on creating and managing
//! spans.
Expand Down Expand Up @@ -173,7 +175,9 @@
//!
//!
//! The following feature flags enable APIs defined in OpenTelemetry specification that is in experimental phase:
//! * `otel_unstable`: Includes unstable APIs. There are no features behind this flag at the moment.
//! * `otel_unstable`: Includes unstable APIs such as
//! `opentelemetry::propagation::EnvVarExtractor` and
//! `opentelemetry::propagation::EnvVarInjector` for environment-variable context propagation.
//!
//! # Related Crates
//!
Expand Down
Loading