sentry-rust icon indicating copy to clipboard operation
sentry-rust copied to clipboard

Sentry Tracing not working for me

Open Hugo-Persson opened this issue 1 year ago • 12 comments

I don't know if I missunderstand the documentation for sentry tracing integration but I can not get event capturing to work. This my test code:

#[tokio::main]
#[tracing::instrument]
async fn main() -> Result<(), Box<dyn Error>> {
    dotenv().ok();
    let _guard = sentry::init((
        "https://...",
        sentry::ClientOptions {
            release: sentry::release_name!(),
            sample_rate: 1.0,
            attach_stacktrace: true,
            ..Default::default()
        },
    ));

    let tracing_layer =
        tracing_subscriber::fmt::layer().with_filter(filter::filter_fn(|metadata| {
            vec![Level::INFO, Level::ERROR, Level::WARN].contains(metadata.level())
        }));
    let sentry_layer = sentry_tracing::layer();
    let _ = tracing_subscriber::registry()
        .with(tracing_layer)
        .with(sentry_layer)
        .init();

    test_sentry();
    const VERSION: &str = env!("CARGO_PKG_VERSION");
    info!("Starting application with version {}", VERSION);
    panic!("A panic");
    Ok(())
}

#[tracing::instrument]
fn test_sentry() {
    error!("Testing");
}

This is my cargo.toml dependencies

[dependencies]
reqwest = { version = "0.11.13", features = ["multipart", "json"] }
tokio = { version = "1.2", features = ["full"] }
serde_json = "1.0"
serde = "1.0"
lapin = "2.1.1"
futures-lite = "1.12.0"
tracing = "0.1.37"
tracing-subscriber = "0.3.16"
tracing-test = "0.1"
dotenv = "0.15.0"
base64 = "0.13.1"
async-trait = "0.1.64"
web-push = "0.9.3"
sentry = {version = "0.23.0", default-features = false, features = ["backtrace", "log", "contexts", "panic", "transport", "reqwest", "rustls", "tracing"]}
lettre = "0.10.2"
regex = "1.5"
sentry-tracing = "0.30.0"

The panic event is recieved in Sentry but not the "Testing" error. Do anyone know what I am doing wrong?

Hugo-Persson avatar Apr 14 '23 08:04 Hugo-Persson

This example does have one problem in it, but I doubt it might be causing this.

Sentry is incompatible with #[tokio::main] in the sense that tokio starts a bunch of worker threads, and calling sentry::init in there means that the configured client is not correctly propagated to all the other threads that were already spawned. However in your example everything is straight-line code without any await in between that might be "work-stealed" to a different thread.

But to be completely safe, please move the sentry::init to the main thread, and spawn the tokio runtime from there. Unfortunately, you have to give up the convenience of #[tokio::main] for that :-(

Swatinem avatar Apr 14 '23 08:04 Swatinem

This example does have one problem in it, but I doubt it might be causing this.

Sentry is incompatible with #[tokio::main] in the sense that tokio starts a bunch of worker threads, and calling sentry::init in there means that the configured client is not correctly propagated to all the other threads that were already spawned. However in your example everything is straight-line code without any await in between that might be "work-stealed" to a different thread.

But to be completely safe, please move the sentry::init to the main thread, and spawn the tokio runtime from there. Unfortunately, you have to give up the convenience of #[tokio::main] for that :-(

Do you have some example code of what you mean? How can I use the async runtime without #[tokio::main]?

Hugo-Persson avatar Apr 14 '23 08:04 Hugo-Persson

https://docs.rs/tokio/latest/tokio/runtime/index.html has some examples.

Swatinem avatar Apr 14 '23 08:04 Swatinem

Ait thank you, I am going to try it and get back to you

Hugo-Persson avatar Apr 14 '23 08:04 Hugo-Persson

This does not work for me, is this how you meant it should look?

fn set_up_tracing() {
    let tracing_layer =
        tracing_subscriber::fmt::layer().with_filter(filter::filter_fn(|metadata| {
            vec![Level::INFO, Level::ERROR, Level::WARN].contains(metadata.level())
        }));
    let sentry_layer = sentry_tracing::layer();
    let _ = tracing_subscriber::registry()
        .with(tracing_layer)
        .with(sentry_layer)
        .init();
}

#[tracing::instrument]
fn main() {
    dotenv().ok();
    let _guard = sentry::init((
        "...",
        sentry::ClientOptions {
            release: sentry::release_name!(),
            sample_rate: 1.0,
            ..Default::default()
        },
    ));

    set_up_tracing();

    const VERSION: &str = env!("CARGO_PKG_VERSION");
    info!("Starting application with version {}", VERSION);
    test_sentry();
}

#[tracing::instrument]
fn test_sentry() {
    error!("Testing");
}

Hugo-Persson avatar Apr 14 '23 09:04 Hugo-Persson

This is pretty close to the code we use ourselves:

https://github.com/getsentry/symbolicator/blob/ddf55813bb3ce01a5285a58539cfb9b1c5a138de/crates/symbolicator/src/logging.rs#L50-L60

Though we use the fmt builder/subscriber directly.

What is the output of the tracing log itself? Also, you can pass the debug: true flag to sentry::ClientOptions and see if that helps with figuring this out.


As a drive-by review: You are using vec![].contains in the filter_fn, which I believe will be called for every event, and will allocate/free a Vec every time.

Swatinem avatar Apr 14 '23 10:04 Swatinem

Thank you for the tip, I have fixed it now. When I pass debug to true I get the following output

[sentry] enabled sentry client for DSN ...
2023-04-14T10:38:38.245827Z  INFO communication_service: Starting application with version 0.1.2
2023-04-14T10:38:38.246747Z ERROR test_sentry: communication_service: Testing
[sentry] dropping client guard -> disposing client
[sentry] client close; request transport to shut down

Hugo-Persson avatar Apr 14 '23 10:04 Hugo-Persson

I'm seeing similar behaviour, any updates?

indiv0 avatar May 25 '23 12:05 indiv0

I am as well. Also confusing is the hello world example in the sentry-tracing readme uses #[tokio::main]?

birwin93 avatar Jun 02 '23 15:06 birwin93

Sentry is incompatible with #[tokio::main] in the sense that tokio starts a bunch of worker threads, and calling sentry::init in there means that the configured client is not correctly propagated to all the other threads that were already spawned. However in your example everything is straight-line code without any await in between that might be "work-stealed" to a different thread.

@Swatinem , is this still the case? The official sentry_tracing crate docs use #[tokio::main] in their example code, but it also seems to have been like that at the time you wrote your comment. If it's still the case, you might want to update the docs.

cmtm avatar Jun 02 '23 21:06 cmtm

@Swatinem any update here?

birwin93 avatar Jun 14 '23 18:06 birwin93

We have updated the docs since then. It seems the doc example was valid in the sense that it compiled, but it did not assert that it actually works correctly.

Either way, your log output does not show that any event / transaction was captured either.

Swatinem avatar Jun 15 '23 08:06 Swatinem