textfile-metrics 0.1.0

Non-blocking Prometheus textfile metrics writer with Counter and Gauge helpers
Documentation
// Copyright (c) Ted Kaplan. All Rights Reserved.
// SPDX-License-Identifier: MIT

//! Basic usage example for textfile-metrics.
//!
//! Run with:
//! ```bash
//! cargo run --example basic_usage
//! ```

use std::time::Duration;

use textfile_metrics::MetricsWriter;
use tokio::time::sleep;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize logging
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::DEBUG)
        .init();

    // Create metrics writer
    let metrics = MetricsWriter::new()?;
    println!(
        "Created metrics writer at: {}",
        metrics.output_path().display()
    );

    // Example 1: Simple counter without labels
    println!("\n=== Example 1: Simple Counter ===");
    let empty: Vec<(&str, &str)> = vec![];
    metrics.counter("requests_total", empty.clone(), 1.0)?;
    metrics.counter("requests_total", empty.clone(), 1.0)?;
    metrics.counter("requests_total", empty.clone(), 1.0)?;
    println!("Incremented requests_total by 3");

    // Example 2: Gauge without labels
    println!("\n=== Example 2: Simple Gauge ===");
    metrics.gauge("temperature_celsius", empty.clone(), 23.5)?;
    println!("Set temperature_celsius to 23.5");

    // Example 3: Metrics with labels
    println!("\n=== Example 3: Metrics with Labels ===");
    let get_labels = vec![
        ("method".to_string(), "GET".to_string()),
        ("status".to_string(), "200".to_string()),
    ];
    let post_labels = vec![
        ("method".to_string(), "POST".to_string()),
        ("status".to_string(), "201".to_string()),
    ];

    metrics.counter("http_requests_total", get_labels.clone(), 100.0)?;
    metrics.counter("http_requests_total", post_labels.clone(), 50.0)?;
    println!("Created http_requests_total with method and status labels");

    // Example 4: Multiple gauge readings
    println!("\n=== Example 4: Multiple Gauges with Location Labels ===");
    for (location, temp) in &[("office", 21.5), ("warehouse", 18.2), ("server_room", 19.8)] {
        let labels = vec![("location".to_string(), location.to_string())];
        metrics.gauge("temperature_celsius", labels, *temp)?;
    }
    println!("Created temperature_celsius gauges for 3 locations");

    // Example 5: Convenience methods
    println!("\n=== Example 5: Convenience Methods ===");
    metrics.inc("requests_received", empty.clone())?;
    metrics.inc("requests_received", empty.clone())?;
    println!("Used inc() to increment requests_received twice");

    metrics.set("active_connections", empty.clone(), 42.0)?;
    println!("Used set() to set active_connections to 42");

    // Example 6: Simulate time-series updates
    println!("\n=== Example 6: Time-series Updates ===");
    for i in 1..=5 {
        let value = 20.0 + (i as f64 * 0.5);
        metrics.gauge("cpu_temperature_celsius", empty.clone(), value)?;
        println!("  Update {}: cpu_temperature = {:.1}°C", i, value);
        sleep(Duration::from_millis(100)).await;
    }

    // Example 7: Error handling
    println!("\n=== Example 7: Error Handling ===");
    match metrics.gauge("invalid", empty.clone(), f64::NAN) {
        Ok(_) => println!("NaN was accepted (unexpected)"),
        Err(e) => println!("NaN correctly rejected: {}", e),
    }

    match metrics.counter("9invalid_name", empty.clone(), 1.0) {
        Ok(_) => println!("Invalid name was accepted (unexpected)"),
        Err(e) => println!("Invalid name correctly rejected: {}", e),
    }

    // Show current state
    println!("\n=== Metrics State ===");
    println!("Total distinct metrics: {}", metrics.len());

    // Flush to disk
    println!("\n=== Flushing Metrics ===");
    metrics.flush().await?;
    println!(
        "Metrics flushed to {}/metrics.prom",
        metrics.output_path().display()
    );

    // Read and display output
    let output_path = metrics.output_path().join("metrics.prom");
    if output_path.exists() {
        let content = std::fs::read_to_string(&output_path)?;
        println!("\n=== Generated metrics.prom ===");
        println!("{}", content);
    }

    Ok(())
}