diff --git a/content/en/tracing/trace_collection/compatibility/rust.md b/content/en/tracing/trace_collection/compatibility/rust.md new file mode 100644 index 0000000000000..7e493f8a523ed --- /dev/null +++ b/content/en/tracing/trace_collection/compatibility/rust.md @@ -0,0 +1,47 @@ +--- +title: Rust Compatibility Requirements +description: 'Compatibility Requirements for the Datadog Rust Tracer' +code_lang: rust +type: multi-code-lang +code_lang_weight: 90 +further_reading: + - link: 'tracing/trace_collection/custom_instrumentation/rust' + tag: 'Documentation' + text: 'Instrument Your Application' + - link: 'https://github.com/DataDog/dd-trace-rs' + tag: "External Site" + text: 'dd-trace-rs repository' +--- + +{{< callout header="false" btn_hidden="true" >}} + The Datadog Rust SDK is in Preview. +{{< /callout >}} + +The Datadog Rust SDK is open source. For more information, see the [`dd-trace-rs` repository][1]. + +## Language and library support + +The Rust SDK relies on specific versions of the Rust compiler and the OpenTelemetry crate. + +| Component | Requirement | +|---|---| +| **Rust Version** | 1.84 (MSRV) | +| **OpenTelemetry Crate** | Version 0.31 | + +## Integrations + +The Datadog Rust SDK does not provide automatic instrumentation. + +You must manually instrument your application using the [OpenTelemetry API][2]. This includes: +- Creating spans for functions or operations. +- Adding attributes (tags) and events to spans. +- Manually propagating trace context for distributed traces. + +For examples, see the [Rust Custom Instrumentation][2] documentation. + +## Further reading + +{{< partial name="whats-next/whats-next.html" >}} + +[1]: https://github.com/DataDog/dd-trace-rs +[2]: /tracing/trace_collection/custom_instrumentation/rust \ No newline at end of file diff --git a/content/en/tracing/trace_collection/custom_instrumentation/rust.md b/content/en/tracing/trace_collection/custom_instrumentation/rust.md index 5b2a4f1179bd9..2a88fc5b03b38 100644 --- a/content/en/tracing/trace_collection/custom_instrumentation/rust.md +++ b/content/en/tracing/trace_collection/custom_instrumentation/rust.md @@ -1,7 +1,10 @@ --- -title: Custom Instrumentation for Rust -description: 'Manually instrument your Rust applications to send custom traces to Datadog.' +title: Rust Custom Instrumentation using the OpenTelemetry API +description: 'Instrument your Rust application with the OpenTelemetry API to send traces to Datadog.' further_reading: + - link: 'https://www.datadoghq.com/blog/monitor-rust-otel/' + tag: 'Blog' + text: 'How to Monitor Your Rust Applications with OpenTelemetry' - link: 'tracing/other_telemetry/connect_logs_and_traces' tag: 'Documentation' text: 'Connect your Logs and Traces together' @@ -10,12 +13,226 @@ further_reading: text: 'Explore your services, resources, and traces' --- -Datadog supports custom instrumentation for Rust applications when you use the [OpenTelemetry SDK][1]. -For more information on setting this up, see [How to Monitor Your Rust Applications with OpenTelemetry][2] on the blog. +{{< callout header="false" btn_hidden="true" >}} + The Datadog Rust SDK is in Preview. +{{< /callout >}} + +Datadog provides support for custom instrumentation in Rust applications through the `datadog-opentelemetry` crate. This library is built on the OpenTelemetry (OTel) API and SDK, providing a tracer that includes Datadog-specific features and an exporter. + +Because this library is built on OpenTelemetry, you use the standard OpenTelemetry API to create traces and spans. + +## Setup + +To configure your Rust application to send OpenTelemetry traces to Datadog, you need to add the correct dependencies and initialize the tracer provider with the Datadog exporter. + +### 1. Add dependencies + +Add `datadog-opentelemetry` and the core `opentelemetry` crate to your `Cargo.toml`. + +```toml +[dependencies] +# The main Datadog OTel library +datadog-opentelemetry = { version = "0.1" } # Note: Update to latest. + +# The OpenTelemetry API for creating spans +opentelemetry = { version = "0.30" } # Note: Update to latest. +``` + +### 2. Initialize the Tracer + +In your application's main function, initialize the Datadog tracer provider. The `tracing().init()` function automatically configures the tracer from environment variables. + +
You must shut down the provider before your application exits to ensure all pending traces are flushed. +
+ + +```rust + +use datadog_opentelemetry; +use opentelemetry::{global, trace::Tracer}; +use std::time::Duration; + +fn main() { + // This picks up env var configuration (like DD_SERVICE) + // and initializes the global tracer provider + let tracer_provider = datadog_opentelemetry::tracing() + .init(); + + // --- Your application code starts here --- + // You can now use the standard OpenTelemetry API + + let tracer = global::tracer("my-component"); + + tracer.in_span("my-operation", |cx| { + // ... do work ... + }); + + println!("Doing work..."); + + // --- Your application code ends here --- + + // Shut down the tracer provider to flush remaining spans + tracer_provider.shutdown_with_timeout(Duration::from_secs(5)).expect("tracer shutdown error"); +} +``` + +### 3. Ensure Agent is running + +The Datadog exporter sends traces to the Datadog Agent, which must be running and accessible. + +## Configuration + +The Datadog Rust SDK is configured using environment variables. For a complete list of options, see the [Configuration documentation][1]. + +## Examples + +After initialization, you use the standard OpenTelemetry API to instrument your code. + +### Get a Tracer + +Get an instance of a `Tracer` from the global provider. + +```rust +use opentelemetry::global; + +let tracer = global::tracer("my-component"); +``` + +### Create a span + +Use `tracer.in_span` (from `opentelemetry::trace::Tracer`) to create a new span that is active for the duration of a closure. + +```rust +use opentelemetry::{global, trace::Tracer}; + +fn do_work() { + let tracer = global::tracer("my-component"); + + tracer.in_span("operation_name", |cx| { + // The span is active within this closure + println!("Doing work..."); + + // Spans are automatically ended when the closure finishes + }); +} +``` + +### Create a child span + +To create a child span, nest `in_span` calls. The inner span automatically becomes a child of the span active in the current context. + +```rust +use opentelemetry::{global, trace::Tracer}; + +fn parent_operation() { + let tracer = global::tracer("my-component"); + + tracer.in_span("parent_operation", |parent_span| { + // parent_span is active + + tracer.in_span("child_operation", |child_span| { + // child_span is active and is a child of parent_span + println!("Doing child work..."); + }); + + println!("Doing parent work..."); + }); +} +``` + +### Access the active span + +To get the currently active span from the context, use `Span::current()`. + +```rust +use opentelemetry::trace::{Span, Tracer}; + +fn do_work_with_active_span() { + let tracer = opentelemetry::global::tracer("my-component"); + + tracer.in_span("my-operation", |cx| { + // 'span' is the active span here. + // You can also get it from the context at any point + // inside this closure: + let current_span = opentelemetry::trace::Span::current(); + + // You can now add attributes or events to it + current_span.set_attribute( + opentelemetry::KeyValue::new("accessed.from.context", true) + ); + }); +} +``` + +### Add span tags + +Add attributes to a span using the `set_attribute` method. In OpenTelemetry, tags are called attributes. + +```rust +use opentelemetry::trace::{Span, Tracer}; +use opentelemetry::KeyValue; + +fn add_tags_to_span() { + let tracer = opentelemetry::global::tracer("my-component"); + + tracer.in_span("operation.with.tags", |cx| { + // Set attributes (tags) on the active span + span.set_attribute(KeyValue::new("customer.id", "12345")); + span.set_attribute(KeyValue::new("http.method", "GET")); + span.set_attribute(KeyValue::new("is.test", true)); + span.set_attribute(KeyValue::new("team.name", "backend")); + + // You can also set multiple attributes at once + span.set_attributes(vec![ + KeyValue::new("resource.name", "/users/list"), + KeyValue::new("db.system", "postgres"), + ]); + }); +} +``` + +### Add span events + +Add time-stamped log messages to a span using the `add_event` method. + +```rust +use opentelemetry::trace::{Span, Tracer}; +use opentelemetry::KeyValue; + +fn add_events_to_span() { + let tracer = opentelemetry::global::tracer("my-component"); + + tracer.in_span("operation.with.events", |cx| { + // Add a simple event + span.add_event("Data received", vec![]); + + // ... some work happens ... + + // Add an event with its own attributes + span.add_event( + "Processing data", + vec![ + KeyValue::new("data.size_bytes", 1024), + KeyValue::new("data.format", "json"), + ], + ); + + // ... more work ... + + span.add_event("Processing complete", vec![]); + }); +} +``` + +## Context propagation + +Because Rust does not have automatic instrumentation, you must manually propagate the trace context when making or receiving remote calls (like HTTP requests) to connect traces across services. + +For more information, see [Trace Context Propagation][2]. ## Further Reading {{< partial name="whats-next/whats-next.html" >}} -[1]: https://opentelemetry.io/docs/instrumentation/ -[2]: https://www.datadoghq.com/blog/monitor-rust-otel/ +[1]: /tracing/trace_collection/library_config/rust +[2]: /tracing/trace_collection/trace_context_propagation/?tab=rust \ No newline at end of file diff --git a/content/en/tracing/trace_collection/library_config/rust.md b/content/en/tracing/trace_collection/library_config/rust.md new file mode 100644 index 0000000000000..036137d163b77 --- /dev/null +++ b/content/en/tracing/trace_collection/library_config/rust.md @@ -0,0 +1,147 @@ +--- +title: Configuring the Rust Tracing Library +code_lang: rust +type: multi-code-lang +code_lang_weight: 80 +further_reading: + - link: 'https://github.com/DataDog/dd-trace-rs' + tag: "Source Code" + text: 'Source code' + - link: "/tracing/trace_collection/trace_context_propagation/" + tag: "Documentation" + text: "Propagating trace context" + - link: 'tracing/glossary/' + tag: 'Documentation' + text: 'Explore your services, resources and traces' +--- + +After you [set up the Rust SDK][1] with your application, you can optionally configure it using the following environment variables. + +## Unified Service Tagging + +It is recommended to use `DD_ENV`, `DD_SERVICE`, and `DD_VERSION` to set `env`, `service`, and `version` for your services. + +`DD_ENV` +: **Default**: `(none)`
+: Set the application's environment, for example: `prod`, `staging`. + +`DD_SERVICE` +: **Default**: `unnamed-rust-service`
+: Sets the service name for your application. + +`DD_VERSION` +: **Default**: `(none)`
+: Set the application's version, for example: `1.2.3` or `6c44da20`. + +`DD_TAGS` +: **Default**: `(none)`
+: A list of default tags to be added to every span, in `key:value` format, separated by commas. Example: `layer:api,team:intake`. + +## Traces + +`DD_TRACE_ENABLED` +: **Default**: `true`
+: Set to `false` to disable tracing. + +`DD_TRACE_STATS_COMPUTATION_ENABLED` +: **Default**: `true`
+: Enable computation of trace statistics. + +`DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH` +: **Default**: `512`
+: Maximum length of the `x-datadog-tags` header in bytes. + +`DD_TRACE_PARTIAL_FLUSH_ENABLED` +: **Default**: `false`
+: Enable partial flushing of traces. + +`DD_TRACE_PARTIAL_FLUSH_MIN_SPANS` +: **Default**: `300`
+: Minimum number of spans in a trace before partial flush is triggered. + +`DD_REMOTE_CONFIGURATION_ENABLED` +: **Default**: `true`
+: Enable or disable remote configuration. Also accepts the alias `DD_REMOTE_CONFIG_ENABLED`. + +`DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS` +: **Default**: `5.0`
+: Interval in seconds for polling remote configuration updates. + +## Agent + +`DD_AGENT_HOST` +: **Default**: `localhost`
+: Sets the hostname of the Datadog Agent. + +`DD_TRACE_AGENT_PORT` +: **Default**: `8126`
+: Sets the port of the Datadog Agent for trace collection. + +`DD_TRACE_AGENT_URL` +: **Default**: `(none)`
+: Sets the URL of the Datadog Agent. Example: `http://localhost:8126`. This takes precedence over `DD_AGENT_HOST` and `DD_TRACE_AGENT_PORT`. + +`DD_DOGSTATSD_HOST` +: **Default**: `localhost`
+: Sets the hostname for DogStatsD metric collection. + +`DD_DOGSTATSD_PORT` +: **Default**: `8125`
+: Sets the port for DogStatsD metric collection. + +`DD_DOGSTATSD_URL` +: **Default**: `(none)`
+: Sets the URL for DogStatsD. This takes precedence over `DD_DOGSTATSD_HOST` and `DD_DOGSTATSD_PORT`. + +`DD_INSTRUMENTATION_TELEMETRY_ENABLED` +: **Default**: `true`
+: Enable or disable telemetry data collection and sending. + +`DD_TELEMETRY_HEARTBEAT_INTERVAL` +: **Default**: `60.0`
+: Interval in seconds for sending telemetry heartbeat messages. + +`DD_TELEMETRY_LOG_COLLECTION_ENABLED` +: **Default**: `true`
+: Enable or disable log collection for telemetry. + +## Logging + +`DD_LOG_LEVEL` +: **Default**: `ERROR`
+: Sets the internal log level for the tracer. Valid values: `DEBUG`, `INFO`, `WARN`, `ERROR`. + +## Sampling + +`DD_TRACE_SAMPLING_RULES` +: **Default**: `(none)`
+: A JSON array of objects to apply for trace sampling. Each rule must have a `sample_rate` between 0.0 and 1.0 (inclusive). + +`DD_TRACE_RATE_LIMIT` +: **Default**: `100`
+: Maximum number of traces to sample per second. + +## Trace context propagation + +`DD_TRACE_PROPAGATION_STYLE` +: **Default**: `datadog,tracecontext`
+: A comma-separated list of propagation styles to use for both extraction and injection. Supported values are `datadog` and `tracecontext`. See [Propagating Rust Trace Context][2] for more information. + +`DD_TRACE_PROPAGATION_STYLE_EXTRACT` +: **Default**: `(none)`
+: A comma-separated list of propagation styles to use for extraction. When set, this overrides `DD_TRACE_PROPAGATION_STYLE` for extraction. + +`DD_TRACE_PROPAGATION_STYLE_INJECT` +: **Default**: `(none)`
+: A comma-separated list of propagation styles to use for injection. When set, this overrides `DD_TRACE_PROPAGATION_STYLE` for injection. + +`DD_TRACE_PROPAGATION_EXTRACT_FIRST` +: **Default**: `false`
+: When set to `true`, stops extracting after the first successful trace context extraction. + +## Further reading + +{{< partial name="whats-next/whats-next.html" >}} + +[1]: /tracing/trace_collection/custom_instrumentation/rust +[2]: /tracing/trace_collection/trace_context_propagation diff --git a/content/en/tracing/trace_collection/trace_context_propagation/_index.md b/content/en/tracing/trace_collection/trace_context_propagation/_index.md index 9c914a0185a47..d1ecb94ae068a 100644 --- a/content/en/tracing/trace_collection/trace_context_propagation/_index.md +++ b/content/en/tracing/trace_collection/trace_context_propagation/_index.md @@ -73,14 +73,16 @@ Most services send and receive trace context headers using the same format. Howe The Datadog SDK supports the following trace context formats: -| Format | Configuration Value | -|------------------------|-------------------------------| -| [Datadog][1] | `datadog` | -| [W3C Trace Context][2] | `tracecontext` | -| [B3 Single][3] | _Language Dependent Value_ | -| [B3 Multi][4] | `b3multi` | -| [Baggage][10] | `baggage` | -| [None][5] | `none` | +| Format | Configuration Value | +|------------------------|----------------------------| +| [Datadog][1] | `datadog` | +| [W3C Trace Context][2] | `tracecontext` | +| [B3 Single][3] | _Language Dependent Value_ | +| [B3 Multi][4] | `b3multi` | +| [Baggage][10] | `baggage`* | +| [None][5] | `none` | + +* **Note**: `baggage` is not supported in Rust. ## Language support @@ -622,6 +624,126 @@ void SetHeaderValues(MessageHeaders headers, string name, string value) {{% /tab %}} +{{% tab "Rust" %}} + +
The Datadog Rust SDK is in Preview.
+ +The Datadog Rust SDK is built on the OpenTelemetry (OTel) SDK. + +Trace context propagation is handled by the OTel SDK, which is configured by `datadog-opentelemetry` to support both `datadog` and `tracecontext` (W3C) formats. + +### Supported formats + +| Format | Configuration Value | +|---|---| +| [Datadog][1] | `datadog` | +| [W3C Trace Context][2] | `tracecontext` | + +### Configuration + +You can control which propagation formats are used by setting the `DD_TRACE_PROPAGATION_STYLE` environment variable. You can provide a comma-separated list. + +For example: + +```bash +# To support both W3C and Datadog +export DD_TRACE_PROPAGATION_STYLE="tracecontext,datadog" +``` + +### Manual injection and extraction + +Because there is no automatic instrumentation for Rust, you must manually propagate context when making or receiving remote calls (like HTTP requests). +- `HeaderExtractor` to **extract** a parent context from incoming request headers. +- `HeaderInjector` to **inject** the current context into outbound request headers. + +First, add `opentelemetry-http` to your `Cargo.toml`: + +```toml +[dependencies] +# Provides HeaderInjector and HeaderExtractor +opentelemetry-http = "" +``` + +
Use the same crate version for opentelemetry-http as the rest of your OpenTelemetry dependencies to avoid version conflicts.
+ +### Injecting context (client side) + +When making an HTTP request (for example, with `hyper`), inject the current span context into the request headers using `HeaderInjector`. + +```rust +use opentelemetry::{global, Context}; +use opentelemetry_http::HeaderInjector; +use http::Request; +use hyper::Body; + +// HYPER example +fn build_outbound_request(url: &str) -> http::Result> { + let cx = Context::current(); + + // Build the request and inject headers in-place + let mut builder = Request::builder().method("GET").uri(url); + global::get_text_map_propagator(|prop| { + prop.inject_context(&cx, &mut HeaderInjector(builder.headers_mut().unwrap())) + }); + + builder.body(Body::empty()) +} +``` + +### Extracting context (server side) + +When receiving an HTTP request (for example, with `hyper`), extract the trace context from the headers using `HeaderExtractor` to parent your new span. + +```rust +use opentelemetry::{ + global, + trace::{Span, FutureExt, SpanKind, Tracer}, + Context, +}; +use opentelemetry_http::HeaderExtractor; +use hyper::{Body, Request, Response}; + +// Utility function to extract context from a hyper request +fn extract_context(req: &Request) -> Context { + global::get_text_map_propagator(|propagator| { + propagator.extract(&HeaderExtractor(req.headers())) + }) +} + +// A placeholder for your actual request handling logic +async fn your_handler_logic() -> Response { + // ... your logic ... + Response::new(Body::from("Hello, World!")) +} + +// HYPER example +async fn hyper_handler(req:Request) -> Response { + // Extract the parent context from the incoming headers + let parent_cx = extract_context(&req); + + let tracer = global::tracer("my-server-component"); + + // Start the server span as a child of the extracted context + let server_span = tracer + .span_builder("http.server.request") + .with_kind(SpanKind::Server) + .start_with_context(tracer, &parent_cx); + + // Create a new context with the new server span + let cx = parent_cx.with_span(server_span); + + // Attach the new context to the future. + // This makes 'server_span' the current span for 'your_handler_logic' + // and any calls it makes. + your_handler_logic().with_context(cx).await +} +``` + +[1]: #datadog-format +[2]: https://www.w3.org/TR/trace-context/ + +{{% /tab %}} + {{< /tabs >}} ## Custom header formats diff --git a/layouts/partials/apm/apm-compatibility.html b/layouts/partials/apm/apm-compatibility.html index 85abc30081f59..1545e41867a51 100644 --- a/layouts/partials/apm/apm-compatibility.html +++ b/layouts/partials/apm/apm-compatibility.html @@ -65,6 +65,13 @@ + {{ $currentURL := .Page.Permalink }} {{ if and (not (in $currentURL "/compatibility/")) (not (in $currentURL "/library_config/")) }} diff --git a/layouts/partials/apm/apm-otel-instrumentation-custom.html b/layouts/partials/apm/apm-otel-instrumentation-custom.html index 429a6f187edc1..e380fbba60187 100644 --- a/layouts/partials/apm/apm-otel-instrumentation-custom.html +++ b/layouts/partials/apm/apm-otel-instrumentation-custom.html @@ -65,6 +65,13 @@ +