tracing-better-stack 0.1.0

A tracing-subscriber layer for Better Stack (Logtail) logging
Documentation
use std::env;
use tracing::{debug, error, info, trace, warn};
use tracing_better_stack::{BetterStackConfig, BetterStackLayer};
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, filter::LevelFilter};

#[tokio::main]
async fn main() {
    // Get the Better Stack ingesting host from environment variable
    // (Better Stack provides unique hosts for each source, e.g., "s1234567.us-east-9.betterstackdata.com")
    let ingesting_host = env::var("BETTER_STACK_INGESTING_HOST")
        .expect("BETTER_STACK_INGESTING_HOST environment variable must be set");

    // Get the Better Stack source token from environment variable
    let source_token = env::var("BETTER_STACK_SOURCE_TOKEN")
        .expect("BETTER_STACK_SOURCE_TOKEN environment variable must be set");

    // Create the Better Stack layer
    let better_stack_layer =
        BetterStackLayer::new(BetterStackConfig::builder(ingesting_host, source_token).build());

    // Create an environment filter
    // This can be configured via the RUST_LOG environment variable
    // Example: RUST_LOG=info,my_module=debug,hyper=warn
    let _env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));

    // Alternative: Create a custom filter programmatically
    let custom_filter = EnvFilter::new("")
        .add_directive("with_filters=trace".parse().unwrap())
        .add_directive("hyper=warn".parse().unwrap())
        .add_directive("reqwest=info".parse().unwrap())
        .add_directive(LevelFilter::INFO.into());

    // Initialize tracing with multiple layers and filters
    tracing_subscriber::registry()
        // Better Stack layer gets all logs at INFO level and above
        .with(better_stack_layer.with_filter(LevelFilter::INFO))
        // Console output uses the environment filter
        .with(
            tracing_subscriber::fmt::layer()
                .with_target(true)
                .compact()
                .with_filter(custom_filter),
        )
        .init();

    // Demonstrate different log levels
    trace!("This trace message will only appear in console if RUST_LOG includes trace");
    debug!("This debug message will only appear in console if RUST_LOG includes debug");
    info!("This info message appears in both console and Better Stack");
    warn!("This warning appears in both console and Better Stack");
    error!("This error appears in both console and Better Stack");

    // Module-specific logging
    module_a::do_work();
    module_b::do_work();

    // Wait for logs to be sent
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;

    info!("Application completed");

    // Wait for final batch
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}

mod module_a {
    use tracing::{debug, info};

    pub fn do_work() {
        info!("Module A: Starting work");
        debug!("Module A: Debug information");
        info!("Module A: Work completed");
    }
}

mod module_b {
    use tracing::{debug, error, info};

    pub fn do_work() {
        info!("Module B: Starting work");
        debug!("Module B: Processing data");

        // Simulate an error condition
        if should_fail() {
            error!("Module B: Operation failed!");
        } else {
            info!("Module B: Work completed successfully");
        }
    }

    fn should_fail() -> bool {
        // For demo purposes
        false
    }
}