sentrystr-tracing 0.1.1

A decentralized error tracking and alerting system using Nostr
Documentation
# SentryStr Tracing

A tracing integration for SentryStr that provides seamless logging and alerting through Nostr relays with optional direct messaging capabilities.

## Features

- **Custom Tracing Layer**: Integrates with the `tracing` ecosystem
- **Structured Logging**: Captures all tracing fields and metadata
- **Direct Messaging**: Optional DM alerts for critical events
- **Level Filtering**: Configurable event level thresholds
- **NIP-17/NIP-44 Support**: Choose between gift wrapping or direct encryption
- **Builder Pattern**: Clean, fluent API for configuration

## Quick Start

### Basic Usage

```rust
use sentrystr_tracing::SentryStrTracingBuilder;
use tracing::{info, warn, error};

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

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

    info!("Application started");
    warn!(cpu_usage = 85.5, "High CPU usage");
    error!(error_code = 500, "Database connection failed");

    Ok(())
}
```

### With Direct Messaging

```rust
use nostr::prelude::*;
use sentrystr_core::Level;
use sentrystr_tracing::{builder::DirectMessageConfig, SentryStrTracingBuilder};

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

    let dm_config = DirectMessageConfig::new(recipient_pubkey, relays.clone())
        .with_min_level(Level::Error)
        .with_nip17(true);

    SentryStrTracingBuilder::new()
        .with_generated_keys_and_relays(relays)
        .with_direct_messaging(dm_config)
        .init()
        .await?;

    // This will send both to Nostr and as a DM
    error!("Critical system failure");

    Ok(())
}
```

## Configuration Options

### Builder Methods

- `with_config(config)` - Use existing SentryStr config
- `with_generated_keys_and_relays(relays)` - Generate new keys
- `with_secret_key_and_relays(key, relays)` - Use specific key
- `with_direct_messaging(dm_config)` - Enable DM alerts
- `with_min_level(level)` - Set minimum tracing level
- `with_fields(include)` - Include/exclude custom fields
- `with_metadata(include)` - Include/exclude tracing metadata

### Direct Message Configuration

```rust
let dm_config = DirectMessageConfig::new(recipient_pubkey, relays)
    .with_min_level(Level::Warning)  // Only warn+ events
    .with_nip17(true);               // Use NIP-17 encryption
```

## Examples

Run the examples to see the integration in action:

```bash
# Basic tracing without DMs
cargo run --example basic_usage

# With direct message alerts
cargo run --example with_direct_messages

# Complex structured logging
cargo run --example custom_fields

# Integration test
cargo run --example integration_test
```

## Integration Patterns

### Web Application

```rust
use axum::{routing::get, Router};
use sentrystr_tracing::SentryStrTracingBuilder;
use tracing::{info, error};

#[tokio::main]
async fn main() {
    SentryStrTracingBuilder::new()
        .with_generated_keys_and_relays(vec!["wss://relay.damus.io".to_string()])
        .init_with_env_filter("info,axum=debug")
        .await
        .expect("Failed to initialize tracing");

    let app = Router::new()
        .route("/", get(|| async { "Hello, World!" }));

    info!("Starting web server on port 3000");
    // Server will automatically log requests through tracing
}
```

### Background Service

```rust
use sentrystr_tracing::SentryStrTracingBuilder;
use tracing::{info, warn, error, instrument};

#[instrument]
async fn process_job(job_id: u64) -> Result<(), Box<dyn std::error::Error>> {
    info!(job_id = job_id, "Processing job");

    // Simulate work
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;

    if job_id % 10 == 0 {
        error!(job_id = job_id, "Job processing failed");
        return Err("Processing failed".into());
    }

    info!(job_id = job_id, "Job completed successfully");
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    SentryStrTracingBuilder::new()
        .with_generated_keys_and_relays(vec!["wss://relay.damus.io".to_string()])
        .with_min_level(tracing::Level::INFO)
        .init()
        .await?;

    for job_id in 1..=20 {
        if let Err(e) = process_job(job_id).await {
            warn!(job_id = job_id, error = %e, "Job failed, will retry");
        }
    }

    Ok(())
}
```

## Advanced Usage

### Custom Event Processing

The layer captures all structured fields from your tracing events:

```rust
error!(
    user_id = 12345,
    error_type = "authentication_failure",
    ip_address = "192.168.1.100",
    user_agent = "Mozilla/5.0...",
    "User authentication failed"
);
```

All fields are preserved in the SentryStr event and available for filtering and alerting.

### Environment-based Configuration

```rust
use std::env;

let dm_enabled = env::var("SENTRYSTR_DM_ENABLED").unwrap_or_default() == "true";
let min_level = env::var("SENTRYSTR_MIN_LEVEL")
    .unwrap_or_else(|_| "info".to_string());

let mut builder = SentryStrTracingBuilder::new()
    .with_generated_keys_and_relays(relays);

if dm_enabled {
    let recipient = env::var("SENTRYSTR_DM_RECIPIENT")?;
    let pubkey = PublicKey::from_bech32(&recipient)?;
    builder = builder.with_dm_recipient(pubkey, relays.clone());
}

builder.init().await?;
```

## Best Practices

1. **Use appropriate log levels** - Don't spam with debug messages
2. **Structure your logs** - Include relevant context fields
3. **Set DM thresholds carefully** - Only alert on actionable events
4. **Use spans for request tracing** - Leverage `#[instrument]`
5. **Configure relay redundancy** - Use multiple relays for reliability

## Performance Considerations

- Events are processed asynchronously to avoid blocking
- DM sending is optional and non-blocking
- Failed Nostr sends are logged but don't crash the application
- Configurable field inclusion to control overhead

## Error Handling

The layer handles errors gracefully:

- Failed Nostr events are logged to stderr
- DM failures don't affect event capture
- Network issues are retried automatically
- Malformed events are skipped with warnings