Skip to content

Flushing the Opentelemetry logger provider in main() results in a flushing timeout error #3796

@wuuer

Description

@wuuer

When using actix-web-rt, flushing the Opentelemetry logger provider with GRPC tonic in main() results in a flushing timeout error. However, flushing within a router function completes without issue.

Expected Behavior

Flushing Opentelemetry logger provider succeeds.

Current Behavior

Flushing Opentelemetry logger results in a timeout error.

Possible Solution

use tokio runtime

replace actix-web::main with tokio::main

Steps to Reproduce (for bugs)

cargo.toml

[package]
name = "actix-web-sample"
version = "0.1.0"
edition = "2024"
 
[dependencies]
actix-web = "4.11.0"
futures-executor = "0.3.31"
tokio = { version = "1.47.1", features = ["macros","rt-multi-thread"] }
opentelemetry_sdk = "0.30.0"
opentelemetry = "0.30.0"
opentelemetry-stdout = "0.30.0"
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic"] }
opentelemetry-appender-tracing = "0.30.1"
anyhow = "1.0.99"
tracing = { version = "0.1.41", features = ["log"] }
tracing-appender = "0.2.3"
tracing-subscriber = { version = "0.3.20", features = ["env-filter","time"] }
tracing-opentelemetry = "0.31.0"

main.rs

use actix_web::{
    App, HttpRequest, HttpServer,
    web::{self, Data},
};
use anyhow::{Ok, Result, anyhow};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::logs::SdkLoggerProvider;
use tracing_subscriber::{Layer, layer::SubscriberExt, util::SubscriberInitExt};
 
async fn index(logger_provider: Data<SdkLoggerProvider>, req: HttpRequest) -> &'static str {
    tracing::info!("REQ: {:?}", req);
    // flushing logs
    if let Err(err) = logger_provider.force_flush() {
        return "flushing error";
    }
    "Hello world!\r\n"
}
 
#[actix_web::main]
async fn main() -> Result<()> {
    let otlp_endpoint = "http://localhost:4317";
 
    let otlp_log_exporter = opentelemetry_otlp::LogExporter::builder()
        .with_tonic()
        .with_endpoint(otlp_endpoint)
        .build()?;
 
    let logger_provider = SdkLoggerProvider::builder()
        .with_batch_exporter(otlp_log_exporter)
        .build();
    tracing_subscriber::registry()
        .with(
            OpenTelemetryTracingBridge::new(&logger_provider)
                .with_filter(tracing::level_filters::LevelFilter::INFO),
        )
        .init();
 
    if let Err(e) = database_setup() {
        tracing::error!("database setup error");
        logger_provider.force_flush()?;
        return Err(e);
    }
 
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(logger_provider.clone()))
            .service(web::resource("/").route(web::get().to(index)))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await?;
 
    Ok(())
}
 
fn database_setup() -> Result<()> {
    // simluate error
    Err(anyhow!("database connection error"))
}

Context

The application can not log the error msg before exit at main()

The batch_log_processor in opentelemetry sdk uses futures_executor::block_on() to flush the log, which appears to cause this issue. But why does flushing within a router function complete without issue?

Your Environment

  • Rust Version (I.e, output of rustc -V): 1.90.0
  • Actix Web Version: 4.11.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions