Skip to content

Commit 6abd036

Browse files
authored
Merge pull request #6 from Validus-Risk-Management/upgrade-to-latest-deps
Version 0.2 supporting more recent versions of dependencies
2 parents 02ce0b0 + 26a2e44 commit 6abd036

File tree

10 files changed

+113
-89
lines changed

10 files changed

+113
-89
lines changed

Cargo.toml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
[package]
22
name = "ddtrace"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
authors = ["David Steiner <david_j_steiner@yahoo.co.nz", "Fergus Strangways-Dixon <fergusdixon101@gmail.com>"]
55
edition = "2021"
66
license = "MIT"
7-
description = "utilities for integrating Datadog with tracing"
7+
description = "Utilities for integrating Datadog with tracing"
88
readme = "README.md"
99
homepage = "https://github.com/Validus-Risk-Management/ddtrace"
1010
repository = "https://github.com/Validus-Risk-Management/ddtrace"
@@ -13,19 +13,25 @@ categories = ["web-programming"]
1313
exclude = [".pre-commit-config.yaml"]
1414

1515
[features]
16-
axum = ["dep:axum", "dep:tokio", "dep:axum-tracing-opentelemetry"]
16+
axum = ["dep:axum-tracing-opentelemetry"]
17+
tonic = ["dep:tonic-tracing-opentelemetry"]
18+
tracing_level_info = [
19+
"axum-tracing-opentelemetry/tracing_level_info",
20+
"tonic-tracing-opentelemetry/tracing_level_info",
21+
]
1722

1823
[dependencies]
19-
axum = { version = "^0.6.10", optional = true }
20-
axum-tracing-opentelemetry = { version = "^0.11.0", optional = true }
21-
chrono = "^0.4.24"
22-
opentelemetry = { version = "^0.19.0", features = ["rt-tokio"] }
23-
opentelemetry-datadog = "^0.7.0"
24-
opentelemetry-otlp = { version = "^0.12.0" }
25-
serde = { version = "^1.0.156", features = ["derive"] }
26-
serde_json = "^1.0.95"
27-
tokio = { version = "^1.26.0", features = ["signal"], optional = true }
28-
tracing = "^0.1.37"
29-
tracing-opentelemetry = "^0.19.0"
30-
tracing-serde = "^0.1.3"
31-
tracing-subscriber = { version = "^0.3.16", features = ["env-filter", "json"] }
24+
axum-tracing-opentelemetry = { version = "0.29", optional = true }
25+
chrono = "0.4"
26+
opentelemetry = "0.30"
27+
opentelemetry_sdk = "0.30"
28+
opentelemetry-datadog = "0.18"
29+
opentelemetry-otlp = { version = "0.30", features = ["grpc-tonic", "http-proto"] }
30+
serde = { version = "1", features = ["derive"] }
31+
serde_json = "1"
32+
thiserror = "2.0.12"
33+
tonic-tracing-opentelemetry = { version = "0.29", optional = true }
34+
tracing = "0.1"
35+
tracing-opentelemetry = "0.31"
36+
tracing-serde = "0.2"
37+
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }

README.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ and Datadog.
1616
# Features
1717

1818
`ddtrace` has the following features:
19+
1920
1. tracing: utilities for building an OpenTelemetry tracer/layer that sends traces to the Datadog agent
20-
2. log correlation: a log formatter that converts the trace ID and span ID to the Datadog native format and injects them into the `dd.trace_id` and `dd.span_id` fields
21+
2. log correlation: a log formatter that converts the trace ID and span ID to the Datadog native format and injects them
22+
into the `dd.trace_id` and `dd.span_id` fields
2123
([more information](https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/opentelemetry/))
2224
3. propagation: a utility function to set the Datadog propagator as the global propagator
23-
4. axum (enabled via the `axum` feature): re-exposing the functionality of [axum-tracing-opentelemetry](https://github.com/davidB/axum-tracing-opentelemetry)
25+
4. axum (enabled via the `axum` feature): re-exposing the functionality
26+
of [axum-tracing-opentelemetry](https://github.com/davidB/axum-tracing-opentelemetry)
2427

2528
# A Complete Example
2629

@@ -32,17 +35,18 @@ use std::net::SocketAddr;
3235
use std::time::Duration;
3336

3437
use axum::{routing::get, Router};
35-
use ddtrace::axum::opentelemetry_tracing_layer;
38+
use ddtrace::axum::OtelAxumLayer;
39+
use ddtrace::error::Error;
3640
use ddtrace::formatter::DatadogFormatter;
3741
use ddtrace::set_global_propagator;
38-
use ddtrace::tracer::{build_layer, TraceResult};
42+
use ddtrace::tracer::build_layer;
3943
use tracing_subscriber::layer::SubscriberExt;
4044
use tracing_subscriber::util::SubscriberInitExt;
4145

4246
#[tokio::main]
43-
async fn main() -> TraceResult<()> {
47+
async fn main() -> Result<(), Error> {
4448
let service_name = std::env::var("DD_SERVICE").unwrap_or("my-service".to_string());
45-
let tracing_layer = build_layer(&service_name)?;
49+
let (tracing_layer, _guard) = build_layer(service_name)?;
4650
tracing_subscriber::registry()
4751
.with(tracing_subscriber::EnvFilter::new(
4852
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()),
@@ -58,16 +62,13 @@ async fn main() -> TraceResult<()> {
5862

5963
let app = Router::new()
6064
.route("/", get(root))
61-
.layer(opentelemetry_tracing_layer())
65+
.layer(OtelAxumLayer::default())
6266
.route("/health", get(health));
6367

6468
let addr = SocketAddr::from(([0, 0, 0, 0], 3025));
69+
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
70+
axum::serve(listener, app).await.unwrap();
6571
tracing::info!("listening on {}", addr);
66-
axum::Server::bind(&addr)
67-
.serve(app.into_make_service())
68-
.with_graceful_shutdown(ddtrace::axum::shutdown_signal())
69-
.await
70-
.unwrap();
7172

7273
Ok(())
7374
}
@@ -109,13 +110,14 @@ to set up the agent.
109110
# Further Context and Rationale
110111

111112
## Exporting Traces
113+
112114
For traces, the official Datadog agent
113115
[can ingest OTel trace data](https://docs.datadoghq.com/opentelemetry/)
114-
with the correct environment variable settings. The traces can be sent
116+
with the correct environment variable settings. The traces can be sent
115117
via either HTTP or gRPC. More information on this can be found
116118
[here](https://docs.datadoghq.com/opentelemetry/otlp_ingest_in_the_agent/?tab=docker).
117119

118-
OpenTelemetry has an official Rust crate with extensions for major
120+
OpenTelemetry has an official Rust crate with extensions for major
119121
formats/providers. This includes a Datadog exporter. We have found
120122
this exporter to be less reliable than the standard OTel exporter
121123
sending data to the OTel endpoint of the Datadog agent, though.
@@ -124,7 +126,8 @@ This crate builds on the OTel exporter.
124126
## Propagation
125127

126128
Two commonly used propagation standards are `B3` (OpenZipkin's propagation style)
127-
and Jaeger. OpenTelemetry [supports both](https://opentelemetry.io/docs/reference/specification/context/api-propagators/#propagators-distribution).
129+
and Jaeger.
130+
OpenTelemetry [supports both](https://opentelemetry.io/docs/reference/specification/context/api-propagators/#propagators-distribution).
128131

129132
Most Datadog SDK's support both `B3` and the Datadog native propagation style.
130133
For example, the Python `ddtrace` library supports `B3` but it
@@ -134,8 +137,8 @@ For ease of integration with services written in other languages that use the of
134137
we opted for sticking with Datadog-style propagation over `B3`. This is set via the
135138
`set_global_propagator` function.
136139

137-
138140
# Reqwest Propagation
141+
139142
The Python library takes care of propagation of the trace context automatically.
140143
Unfortunately, we need to do this manually in Rust.
141144

@@ -154,7 +157,7 @@ use reqwest_tracing::TracingMiddleware;
154157
async fn main() {
155158
set_global_propagator();
156159
client = get_http_client();
157-
160+
158161
// configure tracing, setup your app and inject the client
159162
}
160163

@@ -166,4 +169,5 @@ fn get_http_client() -> ClientWithMiddleware {
166169
```
167170

168171
[crates-badge]: https://img.shields.io/crates/v/ddtrace.svg
172+
169173
[docs-badge]: https://docs.rs/ddtrace/badge.svg

examples/axum/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7-
axum = "^0.6.12"
7+
axum = "0.8.4"
88
ddtrace = { path = "../..", features = ["axum"] }
9-
tokio = { version = "^1.26.0", features = ["macros", "rt-multi-thread"] }
10-
tracing = "^0.1.37"
11-
tracing-subscriber = { version = "^0.3.16", features = ["env-filter", "json"] }
9+
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
10+
tracing = "0.1"
11+
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }

examples/axum/src/main.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ use std::net::SocketAddr;
22
use std::time::Duration;
33

44
use axum::{routing::get, Router};
5-
use ddtrace::axum::opentelemetry_tracing_layer;
5+
use ddtrace::axum::OtelAxumLayer;
6+
use ddtrace::error::Error;
67
use ddtrace::formatter::DatadogFormatter;
78
use ddtrace::set_global_propagator;
8-
use ddtrace::tracer::{build_layer, TraceResult};
9+
use ddtrace::tracer::build_layer;
910
use tracing_subscriber::layer::SubscriberExt;
1011
use tracing_subscriber::util::SubscriberInitExt;
1112

1213
#[tokio::main]
13-
async fn main() -> TraceResult<()> {
14+
async fn main() -> Result<(), Error> {
1415
let service_name = std::env::var("DD_SERVICE").unwrap_or("my-service".to_string());
15-
let tracing_layer = build_layer(&service_name)?;
16+
let (tracing_layer, _guard) = build_layer(service_name)?;
1617
tracing_subscriber::registry()
1718
.with(tracing_subscriber::EnvFilter::new(
1819
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()),
@@ -28,16 +29,13 @@ async fn main() -> TraceResult<()> {
2829

2930
let app = Router::new()
3031
.route("/", get(root))
31-
.layer(opentelemetry_tracing_layer())
32+
.layer(OtelAxumLayer::default())
3233
.route("/health", get(health));
3334

3435
let addr = SocketAddr::from(([0, 0, 0, 0], 3025));
36+
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
37+
axum::serve(listener, app).await.unwrap();
3538
tracing::info!("listening on {}", addr);
36-
axum::Server::bind(&addr)
37-
.serve(app.into_make_service())
38-
.with_graceful_shutdown(ddtrace::axum::shutdown_signal())
39-
.await
40-
.unwrap();
4139

4240
Ok(())
4341
}

src/axum.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,6 @@
33
//! This module re-exposes the middleware layers provided by the
44
//! [`axum-tracing-opentelemetry`] project.
55
//!
6-
//! [`axum-tracing-opentelemetry`]: https://github.com/davidB/axum-tracing-opentelemetry
6+
//! [`axum-tracing-opentelemetry`]: https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk
77
8-
pub use axum_tracing_opentelemetry::opentelemetry_tracing_layer;
9-
pub use axum_tracing_opentelemetry::opentelemetry_tracing_layer_grpc;
10-
11-
pub async fn shutdown_signal() {
12-
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
13-
.expect("failed to install signal handler")
14-
.recv()
15-
.await;
16-
17-
opentelemetry::global::shutdown_tracer_provider();
18-
}
8+
pub use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer};

src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[derive(thiserror::Error, Debug)]
2+
pub enum Error {
3+
#[error(transparent)]
4+
ExporterBuildError(#[from] opentelemetry_otlp::ExporterBuildError),
5+
}

src/formatter.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct TraceInfo {
2929

3030
impl From<TraceId> for DatadogId {
3131
fn from(value: TraceId) -> Self {
32-
let bytes = &value.to_bytes()[std::mem::size_of::<u64>()..std::mem::size_of::<u128>()];
32+
let bytes = &value.to_bytes()[size_of::<u64>()..size_of::<u128>()];
3333
Self(u64::from_be_bytes(bytes.try_into().unwrap()))
3434
}
3535
}
@@ -106,12 +106,9 @@ impl<'a> io::Write for WriteAdaptor<'a> {
106106
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
107107
let s =
108108
std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
109+
self.fmt_write.write_str(s).map_err(io::Error::other)?;
109110

110-
self.fmt_write
111-
.write_str(s)
112-
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
113-
114-
Ok(s.as_bytes().len())
111+
Ok(s.len())
115112
}
116113

117114
fn flush(&mut self) -> io::Result<()> {

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
1212
#[cfg(feature = "axum")]
1313
pub mod axum;
14+
pub mod error;
1415
pub mod formatter;
1516
mod propagator;
17+
#[cfg(feature = "tonic")]
18+
pub mod tonic;
1619
pub mod tracer;
1720

1821
pub use propagator::set_global_propagator;

src/tonic.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//! Tonic utilities.
2+
//!
3+
//! This module re-exposes the middleware layers provided by the
4+
//! [`tonic-tracing-opentelemetry`] project.
5+
//!
6+
//! [`tonic-tracing-opentelemetry`]: https://github.com/davidB/tracing-opentelemetry-instrumentation-sdk
7+
8+
pub use tonic_tracing_opentelemetry::middleware::filters::reject_healthcheck;
9+
pub use tonic_tracing_opentelemetry::middleware::server::{Filter, OtelGrpcLayer, OtelGrpcService};

src/tracer.rs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,53 @@
44
//! to send traces to the Datadog agent in batches over gRPC.
55
//!
66
//! It also contains a convenience function to build a layer with the tracer.
7-
use opentelemetry::sdk::trace::{RandomIdGenerator, Sampler, Tracer};
8-
use opentelemetry::sdk::{trace, Resource};
9-
pub use opentelemetry::trace::{TraceError, TraceResult};
10-
use opentelemetry::KeyValue;
7+
use crate::error::Error;
8+
use opentelemetry::trace::TracerProvider;
119
use opentelemetry_otlp::WithExportConfig;
10+
use opentelemetry_sdk::trace::{RandomIdGenerator, Sampler, SdkTracerProvider, Tracer};
11+
use opentelemetry_sdk::Resource;
1212
use std::time::Duration;
1313
use tracing::Subscriber;
1414
use tracing_opentelemetry::{OpenTelemetryLayer, PreSampledTracer};
1515
use tracing_subscriber::registry::LookupSpan;
1616

17-
pub fn build_tracer(service_name: &str) -> TraceResult<Tracer> {
18-
let exporter = opentelemetry_otlp::new_exporter()
19-
.tonic()
20-
.with_timeout(Duration::from_secs(3));
17+
pub struct ProviderGuard {
18+
tracer_provider: SdkTracerProvider,
19+
}
20+
21+
impl Drop for ProviderGuard {
22+
fn drop(&mut self) {
23+
let _ = self.tracer_provider.force_flush();
24+
let _ = self.tracer_provider.shutdown();
25+
}
26+
}
27+
28+
pub fn build_tracer_provider(service_name: String) -> Result<SdkTracerProvider, Error> {
29+
let exporter = opentelemetry_otlp::SpanExporter::builder()
30+
.with_tonic()
31+
.with_timeout(Duration::from_secs(3))
32+
.build()?;
33+
let resource = Resource::builder().with_service_name(service_name).build();
34+
35+
let provider = SdkTracerProvider::builder()
36+
.with_sampler(Sampler::AlwaysOn)
37+
.with_resource(resource)
38+
.with_id_generator(RandomIdGenerator::default())
39+
.with_batch_exporter(exporter)
40+
.build();
2141

22-
opentelemetry_otlp::new_pipeline()
23-
.tracing()
24-
.with_trace_config(
25-
trace::config()
26-
.with_sampler(Sampler::AlwaysOn)
27-
.with_resource(Resource::new(vec![KeyValue::new(
28-
"service.name",
29-
service_name.to_string(),
30-
)]))
31-
.with_id_generator(RandomIdGenerator::default()),
32-
)
33-
.with_exporter(exporter)
34-
.install_batch(opentelemetry::runtime::Tokio)
42+
Ok(provider)
3543
}
3644

37-
pub fn build_layer<S>(service_name: &str) -> TraceResult<OpenTelemetryLayer<S, Tracer>>
45+
pub fn build_layer<S>(
46+
service_name: String,
47+
) -> Result<(OpenTelemetryLayer<S, Tracer>, ProviderGuard), Error>
3848
where
3949
Tracer: opentelemetry::trace::Tracer + PreSampledTracer + 'static,
4050
S: Subscriber + for<'span> LookupSpan<'span>,
4151
{
42-
let tracer = build_tracer(service_name)?;
43-
Ok(tracing_opentelemetry::layer().with_tracer(tracer))
52+
let tracer_provider = build_tracer_provider(service_name)?;
53+
let layer = tracing_opentelemetry::layer().with_tracer(tracer_provider.tracer(""));
54+
let guard = ProviderGuard { tracer_provider };
55+
Ok((layer, guard))
4456
}

0 commit comments

Comments
 (0)