diff --git a/Cargo.lock b/Cargo.lock index 3e1fccb..e830959 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,42 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-otel-demo" +version = "0.1.0" +dependencies = [ + "axum", + "axum-tracing-opentelemetry", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry-stdout", + "opentelemetry_sdk", + "tokio", + "tower-http", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", +] + +[[package]] +name = "axum-tracing-opentelemetry" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26e978746b0621bff784e6587c91ee79e687c03b1bdc4e77e85ae0958762b802" +dependencies = [ + "axum", + "futures-core", + "futures-util", + "http", + "opentelemetry", + "pin-project-lite", + "tower 0.5.2", + "tracing", + "tracing-opentelemetry", + "tracing-opentelemetry-instrumentation-sdk", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -163,23 +199,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "demo" -version = "0.1.0" -dependencies = [ - "axum", - "opentelemetry", - "opentelemetry-otlp", - "opentelemetry-semantic-conventions", - "opentelemetry-stdout", - "opentelemetry_sdk", - "tokio", - "tower-http", - "tracing", - "tracing-opentelemetry", - "tracing-subscriber", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -1707,6 +1726,18 @@ dependencies = [ "web-time", ] +[[package]] +name = "tracing-opentelemetry-instrumentation-sdk" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab7fa87728e33031354b2764cc8ed37265f2dc8f92543759dab216c15f04a076" +dependencies = [ + "http", + "opentelemetry", + "tracing", + "tracing-opentelemetry", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" diff --git a/demo/Cargo.toml b/demo/Cargo.toml index 4ff44fa..afb5149 100644 --- a/demo/Cargo.toml +++ b/demo/Cargo.toml @@ -1,10 +1,11 @@ [package] -name = "demo" +name = "axum-otel-demo" version = "0.1.0" edition = "2024" [dependencies] axum = "0.8.4" +axum-tracing-opentelemetry = "0.28.0" opentelemetry = { version = "0.29.1", features = ["trace"] } opentelemetry-otlp = { version = "0.29.0", features = ["grpc-tonic", "tonic"] } opentelemetry-semantic-conventions = "0.29.0" diff --git a/demo/src/main.rs b/demo/src/main.rs index 2724908..b5dcee2 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -2,9 +2,13 @@ use axum::{ Router, routing::{get, post}, }; -use opentelemetry::global; +use opentelemetry::{KeyValue, global}; use opentelemetry_otlp::{ExportConfig, WithExportConfig, WithTonicConfig}; -use opentelemetry_sdk::trace::{self, Sampler, SdkTracerProvider}; +use opentelemetry_sdk::{ + Resource, + trace::{self, Sampler, SdkTracerProvider}, +}; +use opentelemetry_semantic_conventions::resource::{self}; use std::{collections::HashMap, iter::Map, net::SocketAddr}; use tower_http::trace::TraceLayer; use tracing::{error, span}; @@ -18,29 +22,37 @@ async fn main() -> Result<(), Box .with_tonic() .build()?; + let service_data = Resource::builder() + .with_attribute(KeyValue::new( + resource::SERVICE_NAME, + env!("CARGO_PKG_NAME"), + )) + .with_attribute(KeyValue::new( + resource::SERVICE_VERSION, + env!("CARGO_PKG_VERSION"), + )) + .build(); + // Create a new OpenTelemetry trace pipeline that prints to stdout let provider = SdkTracerProvider::builder() .with_simple_exporter(opentelemetry_stdout::SpanExporter::default()) - .with_simple_exporter(exporter) + .with_batch_exporter(exporter) + .with_resource(service_data) .build(); - let tracer = provider.tracer("readme_example"); - - // 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); + let tracer = provider.tracer("axum_demo"); - // 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(); + let telemetry_layer = tracing_opentelemetry::layer().with_tracer(tracer); - error!("This event will be logged in the root span."); - }); + tracing_subscriber::registry() + // .with(tracing_subscriber::EnvFilter::from_default_env()) + // .with(tracing_subscriber::fmt::layer()) + // .with( + // tracing_subscriber::EnvFilter::try_from_default_env() + // .unwrap_or_else(|_| format!("{}=trace", env!("CARGO_CRATE_NAME")).into()), + // ) + .with(telemetry_layer) + .init(); // Build the Axum app let app = Router::new() @@ -52,7 +64,8 @@ async fn main() -> Result<(), Box }), ) .route("/work", post(|| async { "Work done!" })) - .layer(TraceLayer::new_for_http()); + .layer(TraceLayer::new_for_http()) + .layer(axum_tracing_opentelemetry::middleware::OtelAxumLayer::default()); // Run the app let address = SocketAddr::from(([127, 0, 0, 1], 3000)); @@ -61,8 +74,6 @@ async fn main() -> Result<(), Box let listener = tokio::net::TcpListener::bind(address).await?; axum::serve(listener, app).await?; - // Shutdown OpenTelemetry - // global::shutdown_tracer_provider(); Ok(()) } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0e2de49 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + jaeger: + image: jaegertracing/jaeger:2.5.0 + ports: + - "16686:16686" + - "4317:4317" + - "4318:4318" + - "5778:5778" + - "9411:9411" diff --git a/opo/src/main.rs b/opo/src/main.rs index 0a233c4..935431d 100644 --- a/opo/src/main.rs +++ b/opo/src/main.rs @@ -15,7 +15,45 @@ impl TraceService for Service { &self, request: Request, ) -> Result, Status> { - tracing::info!("Received request: {:#?}", request); + // tracing::info!("Received request: {:#?}", request); + let data = request.get_ref(); + tracing::info!("Received {} spans", &data.resource_spans.len()); + // tracing::info!("First span: {:#?}", &data.resource_spans.get(0)); + for span in &data.resource_spans { + // tracing::info!("Span: {:#?}", span.resource); + + let Some(resource) = &span.resource else { + continue; + }; + + let attributes: Vec = resource + .attributes + .iter() + .map(|attribute| attribute.key.clone()) + .collect(); + + for attribute in attributes { + if !attribute.starts_with("http") { + continue; + } + + tracing::info!("Attribute: {:?}", attribute); + } + } + + data.resource_spans + .iter() + .flat_map(|span| span.scope_spans.clone()) + .flat_map(|scope_span| scope_span.spans) + .flat_map(|span| span.attributes.clone()) + .for_each(|attribute| { + // + if !attribute.key.starts_with("http") { + return; + } + tracing::info!("Attribute 2: {:?}", attribute.key); + }); + Ok(Response::new(ExportTraceServiceResponse::default())) } } @@ -25,11 +63,7 @@ async fn main() -> Result<(), Box> { tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { - format!( - "{}=trace,tower_http=debug,bollard=debug", - env!("CARGO_CRATE_NAME") - ) - .into() + format!("{}=trace,tower_http=debug", env!("CARGO_CRATE_NAME")).into() }), ) .with(tracing_subscriber::fmt::layer())