use std::sync::Arc;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct QueryMetrics {
pub sql: String,
pub elapsed: Duration,
pub rows_affected: u64,
pub cache_hit: bool,
}
pub type QueryMetricsCallback = Arc<dyn Fn(&QueryMetrics) + Send + Sync>;
#[derive(Clone, Default)]
pub struct ObservabilityConfig {
pub slow_query_threshold: Option<Duration>,
pub on_query: Option<QueryMetricsCallback>,
}
impl std::fmt::Debug for ObservabilityConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ObservabilityConfig")
.field("slow_query_threshold", &self.slow_query_threshold)
.field("on_query", &self.on_query.as_ref().map(|_| ".."))
.finish()
}
}
pub fn log_slow_query(sql: &str, elapsed: Duration, threshold: Duration) {
if elapsed > threshold {
let truncated = if sql.len() > 200 { &sql[..200] } else { sql };
tracing::warn!(
sql = %truncated,
elapsed_ms = %elapsed.as_millis(),
threshold_ms = %threshold.as_millis(),
"slow query detected"
);
}
}
pub fn query_span(sql: &str) -> tracing::Span {
let truncated = if sql.len() > 100 { &sql[..100] } else { sql };
tracing::info_span!("pg.query", db.statement = %truncated)
}