sentrystr-tracing 0.2.0

A decentralized error tracking and alerting system using Nostr
Documentation
use sentrystr_tracing::SentryStrTracingBuilder;
use tracing::{Instrument, error, info, warn};

#[derive(Debug)]
struct User {
    id: u64,
    email: String,
    role: String,
}

async fn authenticate_user(user_id: u64) -> Result<User, String> {
    let span = tracing::info_span!("authenticate_user", user_id = user_id);

    async move {
        info!("Starting user authentication");

        if user_id == 0 {
            error!(
                user_id = user_id,
                error = "invalid_user_id",
                "Authentication failed: invalid user ID"
            );
            return Err("Invalid user ID".to_string());
        }

        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;

        let user = User {
            id: user_id,
            email: format!("user{}@example.com", user_id),
            role: "user".to_string(),
        };

        info!(
            user_id = user.id,
            email = %user.email,
            role = %user.role,
            "User authenticated successfully"
        );

        Ok(user)
    }
    .instrument(span)
    .await
}

async fn process_payment(amount: f64, currency: &str) -> Result<String, String> {
    let span = tracing::info_span!("process_payment", amount = amount, currency = currency);

    async move {
        info!("Processing payment");

        if amount <= 0.0 {
            error!(
                amount = amount,
                currency = currency,
                error = "invalid_amount",
                "Payment failed: invalid amount"
            );
            return Err("Invalid amount".to_string());
        }

        if amount > 10000.0 {
            warn!(
                amount = amount,
                currency = currency,
                threshold = 10000.0,
                "Large payment detected, requires manual review"
            );
        }

        tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;

        let transaction_id = uuid::Uuid::new_v4().to_string();

        info!(
            transaction_id = %transaction_id,
            amount = amount,
            currency = currency,
            status = "completed",
            "Payment processed successfully"
        );

        Ok(transaction_id)
    }
    .instrument(span)
    .await
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let relays = vec![
        "wss://relay.damus.io".to_string(),
        "wss://nos.lol".to_string(),
    ];

    SentryStrTracingBuilder::new()
        .with_generated_keys_and_relays(relays)
        .with_min_level(tracing::Level::INFO)
        .with_fields(true)
        .with_metadata(true)
        .init()
        .await?;

    info!(
        service = "payment_processor",
        version = "2.1.0",
        environment = "production",
        "Service started"
    );

    match authenticate_user(12345).await {
        Ok(user) => {
            info!(
                user_id = user.id,
                operation = "authentication",
                duration_ms = 150,
                "Authentication completed"
            );

            match process_payment(150.75, "USD").await {
                Ok(tx_id) => {
                    info!(
                        transaction_id = %tx_id,
                        user_id = user.id,
                        "Transaction successful"
                    );
                }
                Err(e) => {
                    error!(
                        user_id = user.id,
                        error = %e,
                        "Payment processing failed"
                    );
                }
            }
        }
        Err(e) => {
            error!(
                error = %e,
                "Authentication failed"
            );
        }
    }

    match authenticate_user(0).await {
        Ok(_) => unreachable!(),
        Err(e) => {
            warn!(
                error = %e,
                "Expected authentication failure occurred"
            );
        }
    }

    let large_payment_result = process_payment(15000.0, "EUR").await;
    match large_payment_result {
        Ok(tx_id) => {
            info!(
                transaction_id = %tx_id,
                flags = ?["large_amount", "manual_review"],
                "Large payment completed"
            );
        }
        Err(e) => {
            error!(
                error = %e,
                "Large payment failed"
            );
        }
    }

    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;

    info!(
        shutdown_reason = "graceful",
        uptime_seconds = 30,
        "Service shutting down"
    );

    Ok(())
}