Skip to content

Commit

Permalink
feat: add an example on how to config multiple span processors.
Browse files Browse the repository at this point in the history
* Add an example that export spans to both Jaeger and Zipkin to show how to config multiple span processors/exporters.

* Remove the `with_batch_exporter` function in `TracerProviderBuilder` as it's the same as the `with_span_processor`.

* Rename the `with_default_batch_exporter` function in `TracerProvderBuilder` to `with_batch_exporter` to keep it consistent with the `with_simple_exporter`.

* Add `init_exporter` method in Zipkin's builder to allow user build a zipkin exporter
  • Loading branch information
TommyCpp committed May 5, 2021
1 parent b3623ab commit 38630b8
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 19 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -26,5 +26,6 @@ members = [
"examples/http",
"examples/tracing-grpc",
"examples/zipkin",
"examples/multiple-span-processors"
]
exclude = ["examples/external-otlp-grpcio-async-std"]
10 changes: 10 additions & 0 deletions examples/multiple-span-processors/Cargo.toml
@@ -0,0 +1,10 @@
[package]
name = "multiple-span-processors"
version = "0.1.0"
edition = "2018"

[dependencies]
opentelemetry = { path = "../../opentelemetry", features = ["rt-tokio"] }
opentelemetry-zipkin = { path = "../../opentelemetry-zipkin", default-features=false, features=["reqwest-client"]}
opentelemetry-jaeger = { path = "../../opentelemetry-jaeger", features = ["tokio"] }
tokio = { version = "1.0", features = ["full"] }
17 changes: 17 additions & 0 deletions examples/multiple-span-processors/README.md
@@ -0,0 +1,17 @@
# Work with multiple span processors

Opentelemetry supports export spans into multiple different destinations. One way to do so is to use multiple span processors.

In this example, we demonstrate how to send spans to both Jaeger and Zipkin backend.

To run this example.

1. Start the Jaeger and Zipkin. Run `docker-compose up`

2. Use `cargo run` to run the example.

3. Check the output in Jaeger and Zipkin. The console should also output the SpanData in json format.

4. Use `docker-compose down -v` to tear down the Jaeger and Zipkin backend.


19 changes: 19 additions & 0 deletions examples/multiple-span-processors/docker-compose.yaml
@@ -0,0 +1,19 @@
version: "3"
services:
# Jaeger
jaeger-all-in-one:
image: jaegertracing/all-in-one:1.22
ports:
- "16686:16686"
- "5775:5775/udp"
- "5775:5775/tcp"
- "6831:6831/udp"
- "6832:6832/udp"
- "5778:5778"
- "14628:14628"
- "14250:14250"

zipkin:
image: openzipkin/zipkin
ports:
- "9411:9411"
64 changes: 64 additions & 0 deletions examples/multiple-span-processors/src/main.rs
@@ -0,0 +1,64 @@
use opentelemetry::global::{self, shutdown_tracer_provider};
use opentelemetry::sdk::export::trace::stdout::Exporter as StdoutExporter;
use opentelemetry::sdk::trace::{BatchSpanProcessor, TracerProvider};
use opentelemetry::trace::{mark_span_as_active, TraceError, Tracer};
use opentelemetry::KeyValue;
use std::io::stdout;
use std::time::Duration;

fn init_tracer() -> Result<(), TraceError> {
// build a jaeger batch span processor
let jaeger_processor = BatchSpanProcessor::builder(
opentelemetry_jaeger::new_pipeline()
.with_service_name("trace-demo")
.with_tags(vec![KeyValue::new("exporter", "jaeger")])
.init_exporter()?,
opentelemetry::runtime::Tokio,
)
.build();

// build a zipkin exporter
let zipkin_exporter = opentelemetry_zipkin::new_pipeline()
.with_service_name("trace-demo")
.init_exporter()?;

let provider = TracerProvider::builder()
// We can build a span processor and pass it into provider.
.with_span_processor(jaeger_processor)
// For batch span processor, we can also provide the exporter and runtime and use this
// helper function to build a batch span processor
.with_batch_exporter(zipkin_exporter, opentelemetry::runtime::Tokio)
// Same helper function is also available to build a simple span processor.
.with_simple_exporter(StdoutExporter::new(stdout(), true))
.build();

let _ = global::set_tracer_provider(provider);

Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
init_tracer()?;

let tracer = global::tracer("jaeger-and-zipkin");

{
let span = tracer.start("first span");
let _guard = mark_span_as_active(span);
{
let _inner = tracer.start("first sub span");
tokio::time::sleep(Duration::from_millis(15)).await;
}
{
let _inner = tracer.start("second sub span");
tokio::time::sleep(Duration::from_millis(15)).await;
}
}

tokio::time::sleep(Duration::from_millis(15)).await;

shutdown_tracer_provider();

Ok(())
}
2 changes: 1 addition & 1 deletion opentelemetry-datadog/src/exporter/mod.rs
Expand Up @@ -134,7 +134,7 @@ impl DatadogPipelineBuilder {
let trace_config = self.trace_config.take();
let exporter = self.build_exporter()?;
let mut provider_builder =
sdk::trace::TracerProvider::builder().with_default_batch_exporter(exporter, runtime);
sdk::trace::TracerProvider::builder().with_batch_exporter(exporter, runtime);
if let Some(config) = trace_config {
provider_builder = provider_builder.with_config(config);
}
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry-jaeger/src/exporter/mod.rs
Expand Up @@ -297,7 +297,7 @@ impl PipelineBuilder {
let config = self.config.take();
let exporter = self.init_exporter()?;
let mut builder =
sdk::trace::TracerProvider::builder().with_default_batch_exporter(exporter, runtime);
sdk::trace::TracerProvider::builder().with_batch_exporter(exporter, runtime);
if let Some(config) = config {
builder = builder.with_config(config)
}
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry-otlp/src/lib.rs
Expand Up @@ -581,7 +581,7 @@ fn build_batch_with_exporter<R: Runtime>(
runtime: R,
) -> sdk::trace::Tracer {
let mut provider_builder =
sdk::trace::TracerProvider::builder().with_default_batch_exporter(exporter, runtime);
sdk::trace::TracerProvider::builder().with_batch_exporter(exporter, runtime);
if let Some(config) = trace_config {
provider_builder = provider_builder.with_config(config);
}
Expand Down
11 changes: 7 additions & 4 deletions opentelemetry-zipkin/src/exporter/mod.rs
Expand Up @@ -84,7 +84,10 @@ impl Default for ZipkinPipelineBuilder {
}

impl ZipkinPipelineBuilder {
fn build_exporter(self) -> Result<Exporter, TraceError> {
/// Initial a Zipkin span exporter.
///
/// Returns error if the endpoint is not valid or if no http client is provided.
pub fn init_exporter(self) -> Result<Exporter, TraceError> {
if let Some(client) = self.client {
let endpoint = Endpoint::new(self.service_name, self.service_addr);
let exporter = Exporter::new(
Expand All @@ -103,7 +106,7 @@ impl ZipkinPipelineBuilder {
/// Install the Zipkin trace exporter pipeline with a simple span processor.
pub fn install_simple(mut self) -> Result<sdk::trace::Tracer, TraceError> {
let config = self.trace_config.take();
let exporter = self.build_exporter()?;
let exporter = self.init_exporter()?;
let mut provider_builder =
sdk::trace::TracerProvider::builder().with_simple_exporter(exporter);
if let Some(config) = config {
Expand All @@ -122,9 +125,9 @@ impl ZipkinPipelineBuilder {
runtime: R,
) -> Result<sdk::trace::Tracer, TraceError> {
let config = self.trace_config.take();
let exporter = self.build_exporter()?;
let exporter = self.init_exporter()?;
let mut provider_builder =
sdk::trace::TracerProvider::builder().with_default_batch_exporter(exporter, runtime);
sdk::trace::TracerProvider::builder().with_batch_exporter(exporter, runtime);
if let Some(config) = config {
provider_builder = provider_builder.with_config(config);
}
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry/src/global/trace.rs
Expand Up @@ -486,7 +486,7 @@ mod tests {
use crate::sdk::trace::TracerProvider;
let exporter = crate::sdk::export::trace::stdout::Exporter::new(assert_writer, true);
TracerProvider::builder()
.with_default_batch_exporter(exporter, runtime)
.with_batch_exporter(exporter, runtime)
.build()
}

Expand Down
12 changes: 2 additions & 10 deletions opentelemetry/src/sdk/trace/provider.rs
Expand Up @@ -114,22 +114,14 @@ impl Builder {
Builder { processors, ..self }
}

/// The `BatchProcessor` that this provider should use.
pub fn with_batch_exporter(self, processor: sdk::trace::BatchSpanProcessor) -> Self {
let mut processors = self.processors;
processors.push(Box::new(processor));

Builder { processors, ..self }
}

/// The `SpanExporter` setup using a default `BatchSpanProcessor` that this provider should use.
pub fn with_default_batch_exporter<T: SpanExporter + 'static, R: Runtime>(
pub fn with_batch_exporter<T: SpanExporter + 'static, R: Runtime>(
self,
exporter: T,
runtime: R,
) -> Self {
let batch = sdk::trace::BatchSpanProcessor::builder(exporter, runtime).build();
self.with_batch_exporter(batch)
self.with_span_processor(batch)
}

/// The `SpanProcessor` that this provider should use.
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry/src/sdk/trace/span_processor.rs
Expand Up @@ -200,7 +200,7 @@ impl SpanProcessor for SimpleSpanProcessor {
///
/// // Then use the `with_batch_exporter` method to have the provider export spans in batches.
/// let provider = sdktrace::TracerProvider::builder()
/// .with_batch_exporter(batch)
/// .with_span_processor(batch)
/// .build();
///
/// let _ = global::set_tracer_provider(provider);
Expand Down

0 comments on commit 38630b8

Please sign in to comment.