use metrics::{counter, gauge, histogram};
use metrics_sqlite::SqliteExporter;
use std::time::{Duration, Instant};
use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
const DB_PATH: &str = "chaos.db";
const WORKER_THREADS: usize = 4;
const PER_THREAD_RATE_HZ: u64 = 2_000;
fn main() {
tracing_subscriber::registry()
.with(
EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info,metrics_sqlite=info"))
.unwrap(),
)
.with(fmt::layer())
.init();
let exporter = SqliteExporter::new(Duration::from_millis(250), None, DB_PATH)
.expect("Failed to create SqliteExporter");
exporter
.install()
.expect("Failed to install SqliteExporter");
tracing::info!(
"chaos running: writing to {DB_PATH}, {WORKER_THREADS} threads at ~{PER_THREAD_RATE_HZ} Hz each. Break the DB from another terminal to repro; Ctrl-C to stop."
);
let started = Instant::now();
let mut handles = Vec::new();
for worker_id in 0..WORKER_THREADS {
handles.push(std::thread::spawn(move || {
let period = Duration::from_micros(1_000_000 / PER_THREAD_RATE_HZ);
let mut next = Instant::now();
loop {
counter!("chaos.events", "worker" => worker_id.to_string()).increment(1);
gauge!("chaos.elapsed_secs").set(started.elapsed().as_secs_f64());
histogram!("chaos.iteration_us").record(period.as_micros() as f64);
next += period;
if let Some(remaining) = next.checked_duration_since(Instant::now()) {
std::thread::sleep(remaining);
} else {
next = Instant::now();
}
}
}));
}
for h in handles {
let _ = h.join();
}
}