use clap::{Parser, Subcommand};
use thegent_metrics::domain::entities::{Counter, Gauge, Histogram, Summary};
use thegent_metrics::ports::driven::MetricsPort;
use thegent_metrics::adapters::prometheus::PrometheusFormatter;
use thegent_metrics::adapters::json::JsonFormatter;
use std::sync::Arc;
use dashmap::DashMap;
struct Registry {
counters: DashMap<String, Counter>,
gauges: DashMap<String, Gauge>,
histograms: DashMap<String, Histogram>,
summaries: DashMap<String, Summary>,
}
impl Registry {
fn new() -> Self {
Self {
counters: DashMap::new(),
gauges: DashMap::new(),
histograms: DashMap::new(),
summaries: DashMap::new(),
}
}
}
impl MetricsPort for Registry {
fn register_counter(&self, counter: Counter) -> Result<(), String> {
let name = counter.name().as_str().to_string();
if self.counters.contains_key(&name) {
return Err(format!("Counter '{}' already exists", name));
}
self.counters.insert(name, counter);
Ok(())
}
fn register_gauge(&self, gauge: Gauge) -> Result<(), String> {
let name = gauge.name().as_str().to_string();
if self.gauges.contains_key(&name) {
return Err(format!("Gauge '{}' already exists", name));
}
self.gauges.insert(name, gauge);
Ok(())
}
fn register_histogram(&self, histogram: Histogram) -> Result<(), String> {
let name = histogram.name().as_str().to_string();
if self.histograms.contains_key(&name) {
return Err(format!("Histogram '{}' already exists", name));
}
self.histograms.insert(name, histogram);
Ok(())
}
fn register_summary(&self, summary: Summary) -> Result<(), String> {
let name = summary.name().as_str().to_string();
if self.summaries.contains_key(&name) {
return Err(format!("Summary '{}' already exists", name));
}
self.summaries.insert(name, summary);
Ok(())
}
fn get_counter(&self, name: &str) -> Option<Counter> {
self.counters.get(name).map(|r| r.clone())
}
fn get_gauge(&self, name: &str) -> Option<Gauge> {
self.gauges.get(name).map(|r| r.clone())
}
fn get_histogram(&self, name: &str) -> Option<Histogram> {
self.histograms.get(name).map(|r| r.clone())
}
fn get_summary(&self, name: &str) -> Option<Summary> {
self.summaries.get(name).map(|r| r.clone())
}
fn list_counters(&self) -> Vec<String> {
self.counters.iter().map(|r| r.key().clone()).collect()
}
fn list_gauges(&self) -> Vec<String> {
self.gauges.iter().map(|r| r.key().clone()).collect()
}
fn list_histograms(&self) -> Vec<String> {
self.histograms.iter().map(|r| r.key().clone()).collect()
}
fn list_summaries(&self) -> Vec<String> {
self.summaries.iter().map(|r| r.key().clone()).collect()
}
}
#[derive(Parser)]
#[command(name = "thegent-metrics")]
#[command(about = "High-performance metrics collection CLI")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Counter {
name: String,
},
Gauge {
name: String,
},
Histogram {
name: String,
},
Summary {
name: String,
},
Inc {
name: String,
#[arg(default_value = "1")]
delta: u64,
},
Set {
name: String,
value: f64,
},
Record {
name: String,
value: u64,
},
Observe {
name: String,
value: f64,
},
List,
Show {
name: String,
},
Prometheus,
Json,
Delete {
name: String,
},
Clear,
}
fn main() {
let cli = Cli::parse();
let registry = Arc::new(Registry::new());
match cli.command {
Commands::Counter { name } => {
let counter = Counter::new(&name);
match registry.register_counter(counter) {
Ok(()) => println!("Registered counter: {}", name),
Err(e) => eprintln!("Error: {}", e),
}
}
Commands::Gauge { name } => {
let gauge = Gauge::new(&name);
match registry.register_gauge(gauge) {
Ok(()) => println!("Registered gauge: {}", name),
Err(e) => eprintln!("Error: {}", e),
}
}
Commands::Histogram { name } => {
let histogram = Histogram::new(&name);
match registry.register_histogram(histogram) {
Ok(()) => println!("Registered histogram: {}", name),
Err(e) => eprintln!("Error: {}", e),
}
}
Commands::Summary { name } => {
let summary = Summary::new(&name);
match registry.register_summary(summary) {
Ok(()) => println!("Registered summary: {}", name),
Err(e) => eprintln!("Error: {}", e),
}
}
Commands::Inc { name, delta } => {
if let Some(counter) = registry.get_counter(&name) {
counter.inc(delta);
println!("Incremented {} by {}, new value: {}", name, delta, counter.get());
} else {
eprintln!("Counter '{}' not found", name);
}
}
Commands::Set { name, value } => {
if let Some(gauge) = registry.get_gauge(&name) {
gauge.set(value);
println!("Set {} to {}", name, value);
} else {
eprintln!("Gauge '{}' not found", name);
}
}
Commands::Record { name, value } => {
if let Some(histogram) = registry.get_histogram(&name) {
histogram.record(value);
println!("Recorded {} in {}", value, name);
} else {
eprintln!("Histogram '{}' not found", name);
}
}
Commands::Observe { name, value } => {
if let Some(summary) = registry.get_summary(&name) {
summary.observe(value);
println!("Observed {} in {}", value, name);
} else {
eprintln!("Summary '{}' not found", name);
}
}
Commands::List => {
println!("=== Counters ===");
for name in registry.list_counters() {
if let Some(counter) = registry.get_counter(&name) {
println!(" {} = {}", name, counter.get());
}
}
println!("\n=== Gauges ===");
for name in registry.list_gauges() {
if let Some(gauge) = registry.get_gauge(&name) {
println!(" {} = {}", name, gauge.get());
}
}
println!("\n=== Histograms ===");
for name in registry.list_histograms() {
if let Some(histogram) = registry.get_histogram(&name) {
println!(" {}: count={}, mean={:.2}, p50={:.2}, p99={:.2}",
name, histogram.count(), histogram.mean(), histogram.p50(), histogram.p99());
}
}
println!("\n=== Summaries ===");
for name in registry.list_summaries() {
if let Some(summary) = registry.get_summary(&name) {
println!(" {}: count={}, mean={:.2}", name, summary.count(), summary.mean());
}
}
}
Commands::Show { name } => {
if let Some(counter) = registry.get_counter(&name) {
println!("Counter: {}", name);
println!(" Value: {}", counter.get());
} else if let Some(gauge) = registry.get_gauge(&name) {
println!("Gauge: {}", name);
println!(" Value: {}", gauge.get());
} else if let Some(histogram) = registry.get_histogram(&name) {
println!("Histogram: {}", name);
println!(" Count: {}", histogram.count());
println!(" Sum: {}", histogram.sum());
println!(" Min: {}", histogram.min());
println!(" Max: {}", histogram.max());
println!(" Mean: {:.2}", histogram.mean());
println!(" p50: {:.2}", histogram.p50());
println!(" p90: {:.2}", histogram.p90());
println!(" p99: {:.2}", histogram.p99());
} else if let Some(summary) = registry.get_summary(&name) {
println!("Summary: {}", name);
println!(" Count: {}", summary.count());
println!(" Sum: {:.2}", summary.sum());
println!(" Mean: {:.2}", summary.mean());
} else {
eprintln!("Metric '{}' not found", name);
}
}
Commands::Prometheus => {
println!("{}", PrometheusFormatter::format_registry(&*registry));
}
Commands::Json => {
println!("{}", JsonFormatter::format(&*registry));
}
Commands::Delete { name } => {
let removed = registry.counters.remove(&name).is_some()
|| registry.gauges.remove(&name).is_some()
|| registry.histograms.remove(&name).is_some()
|| registry.summaries.remove(&name).is_some();
if removed {
println!("Deleted: {}", name);
} else {
eprintln!("Metric '{}' not found", name);
}
}
Commands::Clear => {
registry.counters.clear();
registry.gauges.clear();
registry.histograms.clear();
registry.summaries.clear();
println!("Cleared all metrics");
}
}
}