use std::any::Any;
use std::sync::Arc;
use sochdb_kernel::{
Extension, ExtensionCapability, ExtensionInfo, ObservabilityExtension, PluginManager,
};
struct SimpleMetricsPlugin {
name: String,
}
impl SimpleMetricsPlugin {
fn new(name: &str) -> Self {
println!("â
[{}] Plugin created", name);
Self {
name: name.to_string(),
}
}
}
impl Extension for SimpleMetricsPlugin {
fn info(&self) -> ExtensionInfo {
ExtensionInfo {
name: self.name.clone(),
version: "1.0.0".to_string(),
description: "Simple metrics collector for demo".to_string(),
author: "SochDB Demo".to_string(),
capabilities: vec![ExtensionCapability::Observability],
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl ObservabilityExtension for SimpleMetricsPlugin {
fn counter_inc(&self, name: &str, value: u64, labels: &[(&str, &str)]) {
let label_str: Vec<String> = labels.iter().map(|(k, v)| format!("{}={}", k, v)).collect();
println!(
"đ [COUNTER] {} += {} {}",
name,
value,
if label_str.is_empty() {
String::new()
} else {
format!("({})", label_str.join(", "))
}
);
}
fn gauge_set(&self, name: &str, value: f64, labels: &[(&str, &str)]) {
let label_str: Vec<String> = labels.iter().map(|(k, v)| format!("{}={}", k, v)).collect();
println!(
"đ [GAUGE] {} = {:.2} {}",
name,
value,
if label_str.is_empty() {
String::new()
} else {
format!("({})", label_str.join(", "))
}
);
}
fn histogram_observe(&self, name: &str, value: f64, labels: &[(&str, &str)]) {
let label_str: Vec<String> = labels.iter().map(|(k, v)| format!("{}={}", k, v)).collect();
println!(
"đ [HISTOGRAM] {} observed {:.3}ms {}",
name,
value * 1000.0,
if label_str.is_empty() {
String::new()
} else {
format!("({})", label_str.join(", "))
}
);
}
fn span_start(&self, name: &str, parent: Option<u64>) -> u64 {
let span_id = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos() as u64
% 100000;
println!(
"đˇ [SPAN START] {} (id={}, parent={:?})",
name, span_id, parent
);
span_id
}
fn span_end(&self, span_id: u64) {
println!("đļ [SPAN END] id={}", span_id);
}
fn span_event(&self, span_id: u64, name: &str, attributes: &[(&str, &str)]) {
let attr_str: Vec<String> = attributes
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect();
println!(
" ââ [EVENT] {} in span {} {}",
name,
span_id,
if attr_str.is_empty() {
String::new()
} else {
format!("({})", attr_str.join(", "))
}
);
}
fn log_info(&self, message: &str, fields: &[(&str, &str)]) {
let field_str: Vec<String> = fields.iter().map(|(k, v)| format!("{}={}", k, v)).collect();
println!(
"âšī¸ [INFO] {} {}",
message,
if field_str.is_empty() {
String::new()
} else {
format!("| {}", field_str.join(", "))
}
);
}
fn log_error(&self, message: &str, fields: &[(&str, &str)]) {
let field_str: Vec<String> = fields.iter().map(|(k, v)| format!("{}={}", k, v)).collect();
println!(
"â [ERROR] {} {}",
message,
if field_str.is_empty() {
String::new()
} else {
format!("| {}", field_str.join(", "))
}
);
}
}
fn main() {
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ");
println!(" SochDB Plugin System - Observability Demo");
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ\n");
println!("Step 1: Creating PluginManager...");
let plugins = PluginManager::new();
println!(" Has observability before registration: {}\n", plugins.has_observability());
println!("Step 2: Registering custom observability plugin...");
let metrics_plugin = Arc::new(SimpleMetricsPlugin::new("demo-metrics"));
plugins.register_observability(metrics_plugin).unwrap();
println!(" Has observability after registration: {}\n", plugins.has_observability());
println!("Step 3: Listing registered extensions...");
for ext in plugins.list_extensions() {
println!(" - {} v{} ({})", ext.name, ext.version, ext.description);
}
println!();
println!("Step 4: Recording metrics through the plugin...\n");
plugins.counter_inc("sochdb_queries_total", 1, &[("type", "select")]);
plugins.counter_inc("sochdb_queries_total", 1, &[("type", "insert")]);
plugins.counter_inc("sochdb_queries_total", 3, &[("type", "select")]);
plugins.gauge_set("sochdb_connections", 5.0, &[("pool", "primary")]);
plugins.gauge_set("sochdb_buffer_pool_used", 0.73, &[]);
plugins.histogram_observe("sochdb_query_duration", 0.0023, &[("query", "select")]);
plugins.histogram_observe("sochdb_query_duration", 0.0156, &[("query", "insert")]);
println!();
println!("Step 5: Testing spans (distributed tracing)...\n");
plugins.counter_inc("sochdb_transactions_started", 1, &[]);
plugins.counter_inc("sochdb_rows_read", 42, &[("table", "users")]);
plugins.counter_inc("sochdb_transactions_committed", 1, &[]);
println!();
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ");
println!(" â
Demo completed successfully!");
println!("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ");
}