4

I'm learning tracing and open-telemetry in Rust. I feel there are too many concepts and too many crates (at least in Rust) to see traces.

I wrote a simple lib app that adds two u32s:

use std::ops::Add;

pub fn add(f: u32, s: u32) -> u32 {
    let span = tracing::info_span!("Add function", ?f, ?s);
    let _guard = span.enter();
    tracing::info!("Info event");
    f.add(s)
}

And then I'm using the lib in my binary app:

use TracedLibrary::add;
use tracing_opentelemetry::OpenTelemetryLayer;
use tracing_subscriber::util::SubscriberInitExt;
use opentelemetry::{global, sdk::propagation::TraceContextPropagator};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::Registry;

fn main() {
    setup_global_subscriber();
    let sum = add::add(1, 2);
}

fn setup_global_subscriber() {
    global::set_text_map_propagator(TraceContextPropagator::new());
    let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline()
        .with_service_name("trace_demo_2")
        .install().expect("Error initializing Jaeger exporter");
    let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);

    Registry::default()
        .with(telemetry).init();
}

The most confusing part is my apps Cargo.toml which looks like

tracing-subscriber = { version = "0.2.15" }
tracing-opentelemetry = { version= "0.11.0"}
opentelemetry = "0.12.0"
opentelemetry-jaeger = {version = "0.11.0" }

What on earth are those different crates are for? The only crate that makes sense is opentelemetry-jaeger. Are others even required?

And to my main question: I'm running Jaeger's all-in-one docker container. But when I visit http://localhost:16686, I see no traces. Does anyone know what's happening?

kmdreko
  • 42,554
  • 6
  • 57
  • 106
Boss Man
  • 587
  • 2
  • 12
  • The [tracing ecosystem](https://crates.io/crates/tracing#ecosystem) is very modular where integrations with tools and frameworks are separate crates. OpenTelemetry is [also modular](https://github.com/open-telemetry/opentelemetry-rust#ecosystem) allowing exporting to various formats/apis via different crates. So here you go from tracing -> tracing-subscriber -> tracing-opentelemetry -> opentelemetry -> opentelementry-jaeger in order to get tracing to output to jaeger. It may be less crates to just use the opentelemetry tools directly, however I find tracing to be very convenient. – kmdreko Feb 28 '21 at 17:32
  • Your chain is correct. I also think I dont need `opentelemetry` explicitly. The only reason Im adding it as a dep is for this single line `global::set_text_map_propagator(TraceContextPropagator::new());`. I dont know what that line does btw. But anyways, I still dont get any traces or spans. :( – Boss Man Mar 01 '21 at 03:18

2 Answers2

1

Turns out when I create the Jaeger pipeline in setup_global_subscriber(), the _uninstall being returned gets dropped at the end of the function. And when it gets dropped, collector shuts down.

To get traces I had to move contents of setup_global_subscriber() in main().

kmdreko
  • 42,554
  • 6
  • 57
  • 106
Boss Man
  • 587
  • 2
  • 12
  • Maybe you could have your `setup_global_subscriber` function return `_uninstall`, and keep the returned `_uninstall` in the scope of `main`? – Dejavu Nov 21 '21 at 07:27
  • 1
    You may find solace that the API has changed since then and you don't have to worry about managing an `uninstall` variable anymore :) – kmdreko Sep 17 '22 at 03:37
1

I think this is what you need.

    tracing::subscriber::set_global_default(subscriber);

This sets a global Dispatcher, which Dispatcher.inner is your subscriber.

xyJi
  • 11
  • 1