Rust Tracing: Subscriber vs Exporter vs Processor

117 views Asked by At

I'm struggling to understand the differences between a tracing subscriber, exporter, and processor with respect to tracing in Rust. Specifically, I have read that a subscriber is what "listens" for emitted spans, an exporter is what sends this data to external backends, and a processor transforms span data information.

However, when implementing a tracing mechanism in Rust, I have a registry subscriber which has a layer which has a tracer which has both an exporter and a processor (where the processor itself also has an exporter). This has led to some confusion on the purpose of each element and how they all work together?

The purpose of my code was to have a tracing subscriber that would export data to both a Jaeger backend and to a file (both using OTLP formatting). I originally tried creating two OpenTelemetry tracers, each with one exporter, and then adding them both as layers, but there was an error with something panicking here: tracing-subscriber-0.3.11/src/registry/extensions.rs:88:9.

So, I did the following:

let file = File::create("traces/client.txt")?;
let file_exporter = opentelemetry_stdout::SpanExporter::builder()
    .with_writer(file)
    .build();
let file_processor = BatchSpanProcessor::builder(file_exporter, runtime::Tokio).build();
let otlp_exporter = opentelemetry_otlp::new_exporter()
    .tonic()
    .with_endpoint("http://0.0.0.0:4317")
    .build_span_exporter()?;
let tracer = trace::TracerProvider::builder()
    .with_span_processor(file_processor)
    .with_batch_exporter(otlp_exporter, runtime::Tokio)
    .with_config(
        trace::config().with_resource(Resource::new(vec![KeyValue::new(
            "service.name",
            "grpc-client",
        )])),
    )
    .build();
tracing_subscriber::registry()
    .with(tracing_subscriber::EnvFilter::new("INFO"))
    .with(tracing_opentelemetry::layer().with_tracer(tracer.clone().tracer("client_tracer")))
    .try_init()?;

This worked, but I was confused about everything that is happening inside of the tracer variable. Can anyone explain why this works but separating them into two layers does not?

0

There are 0 answers