diff --git a/examples/all-signals/Cargo.toml b/examples/all-signals/Cargo.toml new file mode 100644 index 0000000000..a8e477cae7 --- /dev/null +++ b/examples/all-signals/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "all-signals" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" +rust-version = "1.75.0" +publish = false + +[[bin]] +name = "all-signals" +path = "src/main.rs" +bench = false + +[dependencies] +opentelemetry = { path = "../../opentelemetry" } +opentelemetry_sdk = { path = "../../opentelemetry-sdk" } +opentelemetry-otlp = { workspace = true, features = ["grpc-tonic"] } +tokio = { workspace = true, features = ["full"] } + diff --git a/examples/all-signals/README.md b/examples/all-signals/README.md new file mode 100644 index 0000000000..9ac2f31fb8 --- /dev/null +++ b/examples/all-signals/README.md @@ -0,0 +1,79 @@ +# Getting Started with OpenTelemetry Tracing in Rust + +This tutorial demonstrates how to instrument a Rust application with +OpenTelemetry tracing and visualize the traces using +[Jaeger](https://www.jaegertracing.io/). + +## Running the example + +### Prerequisites + +- **Docker**: Install from [docker.com](https://docs.docker.com/get-docker/) for + running Jaeger locally + +### Step 1: Start Jaeger + +Start Jaeger using Docker: + +```shell +docker run --rm -d --name jaeger \ + -p 16686:16686 \ + -p 4317:4317 \ + cr.jaegertracing.io/jaegertracing/jaeger:2.8.0 +``` + +This exposes: + +- Port `16686`: Jaeger web UI +- Port `4317`: OTLP endpoint for receiving traces + +Verify it's running at + +![Jaeger UI](jaeger-start.png) + +### Step 2: Run the application + +```shell +cargo run +``` + +This will: + +1. Initialize OpenTelemetry with OTLP exporter pointing to `localhost:4317` +2. Create a parent span (`Main operation`) and child span (`Sub operation`) +3. Send the trace data to Jaeger + +### Step 3: View traces in Jaeger + +1. Open [http://localhost:16686](http://localhost:16686) and refresh +2. Select `DemoApp` from the **Service** dropdown +3. Click **Find Traces** + +![Jaeger trace list](jaeger-traces.png) + +Click on a trace to open Trace Details view, which shows the span hierarchy and timing: + +![Jaeger trace details](jaeger-trace-details.png) + +You'll see the `Main operation` span containing the `Sub operation` span, along +with their timing information and any attributes or events. + +## Data flow + +```mermaid +graph LR + A[Rust App] -->|OTLP| B[Jaeger] + B --> C[Web UI] +``` + +### Cleanup + +```shell +docker stop jaeger +``` + +## Next steps (TODO) + +- Add metrics and logs instrumentation +- Add sampling and context propagation +- Add distributed tracing across multiple services diff --git a/examples/all-signals/jaeger-start.png b/examples/all-signals/jaeger-start.png new file mode 100644 index 0000000000..4013afb7f0 Binary files /dev/null and b/examples/all-signals/jaeger-start.png differ diff --git a/examples/all-signals/jaeger-trace-details.png b/examples/all-signals/jaeger-trace-details.png new file mode 100644 index 0000000000..f795f35708 Binary files /dev/null and b/examples/all-signals/jaeger-trace-details.png differ diff --git a/examples/all-signals/jaeger-traces.png b/examples/all-signals/jaeger-traces.png new file mode 100644 index 0000000000..092d0c0f5c Binary files /dev/null and b/examples/all-signals/jaeger-traces.png differ diff --git a/examples/all-signals/src/main.rs b/examples/all-signals/src/main.rs new file mode 100644 index 0000000000..ad47f002f8 --- /dev/null +++ b/examples/all-signals/src/main.rs @@ -0,0 +1,55 @@ +use opentelemetry::global; +use opentelemetry::trace::{TraceContextExt, Tracer}; +use opentelemetry::KeyValue; +use opentelemetry_otlp::SpanExporter; +use opentelemetry_sdk::trace::SdkTracerProvider; +use opentelemetry_sdk::Resource; +use std::sync::OnceLock; +use std::time::Duration; + +fn get_resource() -> Resource { + static RESOURCE: OnceLock = OnceLock::new(); + RESOURCE + .get_or_init(|| Resource::builder().with_service_name("DemoApp").build()) + .clone() +} + +fn init_traces() -> SdkTracerProvider { + let exporter = SpanExporter::builder() + .with_tonic() + .build() + .expect("Failed to create span exporter"); + SdkTracerProvider::builder() + .with_resource(get_resource()) + .with_batch_exporter(exporter) + .build() +} + +#[tokio::main] +async fn main() { + let tracer_provider = init_traces(); + global::set_tracer_provider(tracer_provider.clone()); + let tracer = global::tracer("my-application"); + + tracer.in_span("Main operation", |cx| { + let span = cx.span(); + span.set_attribute(KeyValue::new("operation.name", "demo")); + + // Simulate some work + std::thread::sleep(Duration::from_millis(200)); + + tracer.in_span("Sub operation", |cx| { + let span = cx.span(); + span.set_attribute(KeyValue::new("operation.type", "processing")); + + // Simulate sub-operation work + std::thread::sleep(Duration::from_millis(50)); + + span.add_event("Processing completed", vec![]); + }); + }); + + tracer_provider + .shutdown() + .expect("Failed to shutdown tracer provider"); +}