use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Default)]
pub struct Metrics {
pub sql_queries: AtomicU64,
pub sql_errors: AtomicU64,
pub slow_queries: AtomicU64,
pub puts: AtomicU64,
pub commits: AtomicU64,
pub txns: AtomicU64,
}
impl Metrics {
#[inline]
pub fn inc_sql_queries(&self) {
self.sql_queries.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn inc_sql_errors(&self) {
self.sql_errors.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn inc_slow_queries(&self) {
self.slow_queries.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn inc_puts(&self) {
self.puts.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn inc_commits(&self) {
self.commits.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn inc_txns(&self) {
self.txns.fetch_add(1, Ordering::Relaxed);
}
pub fn prometheus_text(&self, table_count: usize) -> String {
let sql_queries = self.sql_queries.load(Ordering::Relaxed);
let sql_errors = self.sql_errors.load(Ordering::Relaxed);
let slow_queries = self.slow_queries.load(Ordering::Relaxed);
let puts = self.puts.load(Ordering::Relaxed);
let commits = self.commits.load(Ordering::Relaxed);
let txns = self.txns.load(Ordering::Relaxed);
let mut out = String::with_capacity(1024);
out.push_str("# HELP mongreldb_sql_queries_total Total /sql requests received.\n");
out.push_str("# TYPE mongreldb_sql_queries_total counter\n");
out.push_str(&format!("mongreldb_sql_queries_total {sql_queries}\n\n"));
out.push_str("# HELP mongreldb_sql_errors_total /sql requests that returned an error.\n");
out.push_str("# TYPE mongreldb_sql_errors_total counter\n");
out.push_str(&format!("mongreldb_sql_errors_total {sql_errors}\n\n"));
out.push_str(
"# HELP mongreldb_slow_queries_total /sql requests above the slow-query threshold.\n",
);
out.push_str("# TYPE mongreldb_slow_queries_total counter\n");
out.push_str(&format!("mongreldb_slow_queries_total {slow_queries}\n\n"));
out.push_str("# HELP mongreldb_puts_total Single-row put requests.\n");
out.push_str("# TYPE mongreldb_puts_total counter\n");
out.push_str(&format!("mongreldb_puts_total {puts}\n\n"));
out.push_str("# HELP mongreldb_commits_total Explicit table commit requests.\n");
out.push_str("# TYPE mongreldb_commits_total counter\n");
out.push_str(&format!("mongreldb_commits_total {commits}\n\n"));
out.push_str("# HELP mongreldb_txns_total Atomic /txn batch requests.\n");
out.push_str("# TYPE mongreldb_txns_total counter\n");
out.push_str(&format!("mongreldb_txns_total {txns}\n\n"));
out.push_str("# HELP mongreldb_tables Current number of tables.\n");
out.push_str("# TYPE mongreldb_tables gauge\n");
out.push_str(&format!("mongreldb_tables {table_count}\n"));
out
}
}
pub fn slow_query_threshold() -> std::time::Duration {
const DEFAULT_MS: u64 = 100;
let ms = std::env::var("MONGRELBL_SLOW_QUERY_MS")
.ok()
.and_then(|v| v.parse::<u64>().ok())
.unwrap_or(DEFAULT_MS);
std::time::Duration::from_millis(ms.max(1))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prometheus_text_contains_all_series_and_types() {
let m = Metrics::default();
m.inc_sql_queries();
m.inc_sql_queries();
m.inc_sql_errors();
m.inc_slow_queries();
m.inc_puts();
m.inc_commits();
m.inc_txns();
let body = m.prometheus_text(3);
assert!(body.contains("# TYPE mongreldb_sql_queries_total counter"));
assert!(body.contains("# TYPE mongreldb_sql_errors_total counter"));
assert!(body.contains("# TYPE mongreldb_slow_queries_total counter"));
assert!(body.contains("# TYPE mongreldb_puts_total counter"));
assert!(body.contains("# TYPE mongreldb_commits_total counter"));
assert!(body.contains("# TYPE mongreldb_txns_total counter"));
assert!(body.contains("# TYPE mongreldb_tables gauge"));
assert!(body.contains("mongreldb_sql_queries_total 2"));
assert!(body.contains("mongreldb_sql_errors_total 1"));
assert!(body.contains("mongreldb_slow_queries_total 1"));
assert!(body.contains("mongreldb_puts_total 1"));
assert!(body.contains("mongreldb_commits_total 1"));
assert!(body.contains("mongreldb_txns_total 1"));
assert!(body.contains("mongreldb_tables 3"));
}
#[test]
fn default_threshold_is_100ms() {
if std::env::var("MONGRELBL_SLOW_QUERY_MS").is_err() {
assert_eq!(
slow_query_threshold(),
std::time::Duration::from_millis(100)
);
}
}
}