Skip to content

Commit a142280

Browse files
committed
feat: Add declarative configuration initial version.
1 parent cff5728 commit a142280

28 files changed

+1661
-143
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"opentelemetry-*",
55
"opentelemetry-*/examples/*",
66
"opentelemetry-otlp/tests/*",
7+
"opentelemetry-declarative-config",
78
"examples/*",
89
"stress",
910
]
@@ -81,7 +82,6 @@ schemars = "0.8"
8182
sysinfo = "0.32"
8283
tempfile = "3.3.0"
8384
tracing-log = "0.2"
84-
tracing-opentelemetry = "0.32"
8585
typed-builder = "0.20"
8686
uuid = "1.3"
8787
pprof = { version = "0.14", features = ["flamegraph", "criterion"] }

opentelemetry-appender-tracing/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
## vNext
44

5+
- Remove the `experimental_use_tracing_span_context` since
6+
`tracing-opentelemetry` now supports [activating][31901] the OpenTelemetry
7+
context for the current tracing span.
8+
9+
This fixes [3190][3190] the circular dependency introduced by depending on
10+
`tracing-opentelemetry` that depends on `opentelemetry`.
11+
12+
[3190]: https://github.com/open-telemetry/opentelemetry-rust/issues/3190
13+
[31901]: https://github.com/tokio-rs/tracing-opentelemetry/blob/884b00cf438557733bd9cef9456281bea8c4bea1/src/layer.rs#L842
14+
515
## 0.31.1
616

717
Released 2025-Oct-1

opentelemetry-appender-tracing/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ tracing = { workspace = true, features = ["std"]}
1818
tracing-core = { workspace = true }
1919
tracing-log = { workspace = true, optional = true }
2020
tracing-subscriber = { workspace = true, features = ["registry", "std"] }
21-
tracing-opentelemetry = { workspace = true, optional = true }
2221

2322
[dev-dependencies]
2423
log = { workspace = true }
@@ -28,7 +27,6 @@ tracing = { workspace = true, features = ["std"]}
2827
tracing-subscriber = { workspace = true, features = ["env-filter","registry", "std", "fmt"] }
2928
tracing-log = { workspace = true }
3029
criterion = { workspace = true }
31-
#tokio = { workspace = true, features = ["full"]}
3230

3331
[target.'cfg(not(target_os = "windows"))'.dev-dependencies]
3432
pprof = { workspace = true }
@@ -37,10 +35,8 @@ pprof = { workspace = true }
3735
default = []
3836
experimental_metadata_attributes = ["dep:tracing-log"]
3937
spec_unstable_logs_enabled = ["opentelemetry/spec_unstable_logs_enabled"]
40-
experimental_use_tracing_span_context = ["tracing-opentelemetry"]
4138
bench_profiling = []
4239

43-
4440
[[bench]]
4541
name = "logs"
4642
harness = false

opentelemetry-appender-tracing/src/layer.rs

Lines changed: 0 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -244,29 +244,6 @@ where
244244
// Visit fields.
245245
event.record(&mut visitor);
246246

247-
#[cfg(feature = "experimental_use_tracing_span_context")]
248-
if let Some(span) = _ctx.event_span(event) {
249-
use tracing_opentelemetry::OtelData;
250-
if let Some(otd) = span.extensions().get::<OtelData>() {
251-
if let Some(span_id) = otd.span_id() {
252-
// Try the trace_id of the current span first;
253-
// If it is not already established (still in the Builder state), try finding the root span.
254-
let opt_trace_id = otd.trace_id().or_else(|| {
255-
span.scope().last().and_then(|root_span| {
256-
root_span
257-
.extensions()
258-
.get::<OtelData>()
259-
.and_then(|root_otd| root_otd.trace_id())
260-
})
261-
});
262-
if let Some(trace_id) = opt_trace_id {
263-
// Unable to reliably obtain TraceFlags (old implementation also passed None)
264-
log_record.set_trace_context(trace_id, span_id, None);
265-
}
266-
}
267-
}
268-
}
269-
270247
//emit record
271248
self.logger.emit(log_record);
272249
}
@@ -611,121 +588,6 @@ mod tests {
611588
}
612589
}
613590

614-
#[cfg(feature = "experimental_use_tracing_span_context")]
615-
#[test]
616-
fn tracing_appender_inside_tracing_crate_context() {
617-
use opentelemetry::{trace::SpanContext, Context, SpanId, TraceId};
618-
use opentelemetry_sdk::trace::InMemorySpanExporterBuilder;
619-
use tracing_opentelemetry::OpenTelemetrySpanExt;
620-
621-
// Arrange
622-
let exporter: InMemoryLogExporter = InMemoryLogExporter::default();
623-
let logger_provider = SdkLoggerProvider::builder()
624-
.with_simple_exporter(exporter.clone())
625-
.build();
626-
627-
// setup tracing layer to compare trace/span IDs against
628-
let span_exporter = InMemorySpanExporterBuilder::new().build();
629-
let tracer_provider = SdkTracerProvider::builder()
630-
.with_simple_exporter(span_exporter.clone())
631-
.build();
632-
let tracer = tracer_provider.tracer("test-tracer");
633-
634-
let level_filter = tracing_subscriber::filter::LevelFilter::ERROR;
635-
let log_layer =
636-
layer::OpenTelemetryTracingBridge::new(&logger_provider).with_filter(level_filter);
637-
638-
let subscriber = tracing_subscriber::registry()
639-
.with(log_layer)
640-
.with(tracing_opentelemetry::layer().with_tracer(tracer));
641-
642-
// Avoiding global subscriber.init() as that does not play well with unit tests.
643-
let _guard = tracing::subscriber::set_default(subscriber);
644-
645-
// Act
646-
tracing::error_span!("outer-span").in_scope(|| {
647-
error!("first-event");
648-
649-
tracing::error_span!("inner-span").in_scope(|| {
650-
error!("second-event");
651-
});
652-
});
653-
654-
assert!(logger_provider.force_flush().is_ok());
655-
656-
let logs = exporter.get_emitted_logs().expect("No emitted logs");
657-
assert_eq!(logs.len(), 2, "Expected 2 logs, got: {logs:?}");
658-
659-
let spans = span_exporter.get_finished_spans().unwrap();
660-
assert_eq!(spans.len(), 2);
661-
662-
let trace_id = spans[0].span_context.trace_id();
663-
assert_eq!(trace_id, spans[1].span_context.trace_id());
664-
let inner_span_id = spans[0].span_context.span_id();
665-
let outer_span_id = spans[1].span_context.span_id();
666-
assert_eq!(outer_span_id, spans[0].parent_span_id);
667-
668-
let trace_ctx0 = logs[0].record.trace_context().unwrap();
669-
let trace_ctx1 = logs[1].record.trace_context().unwrap();
670-
671-
assert_eq!(trace_ctx0.trace_id, trace_id);
672-
assert_eq!(trace_ctx1.trace_id, trace_id);
673-
assert_eq!(trace_ctx0.span_id, outer_span_id);
674-
assert_eq!(trace_ctx1.span_id, inner_span_id);
675-
676-
// Set context from remote.
677-
let remote_trace_id = TraceId::from(233);
678-
let remote_span_id = SpanId::from(2333);
679-
let remote_span_context = SpanContext::new(
680-
remote_trace_id,
681-
remote_span_id,
682-
TraceFlags::SAMPLED,
683-
true,
684-
Default::default(),
685-
);
686-
687-
// Act again.
688-
{
689-
let parent_context = Context::current().with_remote_span_context(remote_span_context);
690-
let outer_span = tracing::error_span!("outer-span");
691-
let _ = outer_span.set_parent(parent_context);
692-
693-
outer_span.in_scope(|| {
694-
error!("first-event");
695-
696-
let inner_span = tracing::error_span!("inner-span");
697-
inner_span.in_scope(|| {
698-
error!("second-event");
699-
});
700-
});
701-
}
702-
703-
assert!(logger_provider.force_flush().is_ok());
704-
705-
let logs = exporter.get_emitted_logs().expect("No emitted logs");
706-
assert_eq!(logs.len(), 4, "Expected 4 logs, got: {logs:?}");
707-
let logs = &logs[2..];
708-
709-
let spans = span_exporter.get_finished_spans().unwrap();
710-
assert_eq!(spans.len(), 4);
711-
let spans = &spans[2..];
712-
713-
let trace_id = spans[0].span_context.trace_id();
714-
assert_eq!(trace_id, remote_trace_id);
715-
assert_eq!(trace_id, spans[1].span_context.trace_id());
716-
let inner_span_id = spans[0].span_context.span_id();
717-
let outer_span_id = spans[1].span_context.span_id();
718-
assert_eq!(outer_span_id, spans[0].parent_span_id);
719-
720-
let trace_ctx0 = logs[0].record.trace_context().unwrap();
721-
let trace_ctx1 = logs[1].record.trace_context().unwrap();
722-
723-
assert_eq!(trace_ctx0.trace_id, trace_id);
724-
assert_eq!(trace_ctx1.trace_id, trace_id);
725-
assert_eq!(trace_ctx0.span_id, outer_span_id);
726-
assert_eq!(trace_ctx1.span_id, inner_span_id);
727-
}
728-
729591
#[test]
730592
fn tracing_appender_standalone_with_tracing_log() {
731593
// Arrange
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Changelog
2+
3+
## vNext
4+
5+
## v0.1.0
6+
7+
### Added
8+
9+
- Initial declarative configuration
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
[package]
2+
name = "opentelemetry-declarative-config"
3+
version = "0.29.1"
4+
description = "Declarative configuration for OpenTelemetry SDK"
5+
homepage = "https://github.com/open-telemetry/opentelemetry-rust/tree/main/opentelemetry-declarative-config"
6+
repository = "https://github.com/open-telemetry/opentelemetry-rust/tree/main/opentelemetry-declarative-config"
7+
readme = "README.md"
8+
categories = [
9+
"development-tools::debugging",
10+
"development-tools::profiling",
11+
]
12+
keywords = ["opentelemetry", "declarative", "metrics", "configuration"]
13+
license = "Apache-2.0"
14+
edition = "2021"
15+
rust-version = "1.75.0"
16+
17+
[package.metadata.docs.rs]
18+
all-features = true
19+
rustdoc-args = ["--cfg", "docsrs"]
20+
21+
[dependencies]
22+
opentelemetry = { version = "0.31.0" }
23+
opentelemetry_sdk = { version = "0.31.0", features = ["experimental_metrics_custom_reader"] }
24+
opentelemetry-stdout = { version = "0.31.0" }
25+
opentelemetry-otlp = { version = "0.31.0" }
26+
opentelemetry-http = { workspace = true, optional = true, default-features = false }
27+
serde = { workspace = true, features = ["derive"] }
28+
reqwest = { workspace = true, optional = true }
29+
serde_yaml = "0.9.34"
30+
31+
[dev-dependencies]
32+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
33+
34+
[features]
35+
tonic-client = ["opentelemetry-otlp/grpc-tonic", "opentelemetry-otlp/trace", "opentelemetry-otlp/logs", "opentelemetry-otlp/metrics"]
36+
hyper-client = ["opentelemetry-http/hyper"]
37+
reqwest-client = ["reqwest", "opentelemetry-http/reqwest"]
38+
reqwest-blocking-client = ["reqwest/blocking", "opentelemetry-http/reqwest-blocking"]
39+
40+
# Keep tonic as the default client
41+
default = ["tonic-client"]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# OpenTelemetry Declarative Configuration
2+
3+
![OpenTelemetry — An observability framework for cloud-native software.][splash]
4+
5+
[splash]: https://raw.githubusercontent.com/open-telemetry/opentelemetry-rust/main/assets/logo-text.png
6+
7+
Declarative configuration for applications instrumented with [`OpenTelemetry`].
8+
9+
## OpenTelemetry Overview
10+
11+
OpenTelemetry is an Observability framework and toolkit designed to create and
12+
manage telemetry data such as traces, metrics, and logs. OpenTelemetry is
13+
vendor- and tool-agnostic, meaning that it can be used with a broad variety of
14+
Observability backends, including open source tools like [Jaeger] and
15+
[Prometheus], as well as commercial offerings.
16+
17+
OpenTelemetry is *not* an observability backend like Jaeger, Prometheus, or other
18+
commercial vendors. OpenTelemetry is focused on the generation, collection,
19+
management, and export of telemetry. A major goal of OpenTelemetry is that you
20+
can easily instrument your applications or systems, no matter their language,
21+
infrastructure, or runtime environment. Crucially, the storage and visualization
22+
of telemetry is intentionally left to other tools.
23+
24+
[`Prometheus`]: https://prometheus.io
25+
[`OpenTelemetry`]: https://crates.io/crates/opentelemetry
26+
[`Jaeger`]: https://www.jaegertracing.io
27+
28+
## Release Notes
29+
30+
You can find the release notes (changelog) [here](https://github.com/open-telemetry/opentelemetry-rust/blob/main/opentelemetry-declarative-config/CHANGELOG.md).
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use opentelemetry_declarative_config::Configurator;
2+
3+
/// Example of configuring OpenTelemetry telemetry using declarative YAML configuration.
4+
5+
#[tokio::main]
6+
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
7+
let configurator = Configurator::new();
8+
let config_yaml = r#"
9+
metrics:
10+
readers:
11+
- periodic:
12+
exporter:
13+
otlp:
14+
protocol: http/protobuf
15+
endpoint: https://backend:4318
16+
stdout:
17+
temporality: cumulative
18+
logs:
19+
processors:
20+
- batch:
21+
exporter:
22+
stdout:
23+
otlp:
24+
protocol: http/protobuf
25+
endpoint: https://backend:4318
26+
resource:
27+
service.name: sample-service
28+
service.version: "1.0.0"
29+
"#;
30+
let result = configurator.configure_telemetry_from_yaml(config_yaml.into());
31+
if let Err(ref e) = result {
32+
panic!("Failed to configure telemetry from YAML string: {}", e);
33+
}
34+
assert!(result.is_ok());
35+
let telemetry_providers = result.unwrap();
36+
assert!(telemetry_providers.meter_provider().is_some());
37+
assert!(telemetry_providers.logs_provider().is_some());
38+
assert!(telemetry_providers.traces_provider().is_none());
39+
40+
println!("All the expected telemetry providers were configured successfully. Shutting down...");
41+
42+
telemetry_providers.shutdown()?;
43+
Ok(())
44+
}

0 commit comments

Comments
 (0)