use std::sync::Once; use std::time::Instant; use metrics::{Unit, counter, describe_counter, describe_histogram, histogram}; pub const OUTCOME_SUCCESS: &str = "success"; pub const OUTCOME_ERROR: &str = "error"; pub const OUTCOME_ACQUIRED: &str = "acquired"; pub const OUTCOME_REJECTED: &str = "rejected"; static DESCRIBE_ONCE: Once = Once::new(); pub fn ensure_described() { DESCRIBE_ONCE.call_once(describe_all); } fn describe_all() { describe_counter!( "gitssh_sessions_total", "SSH client sessions partitioned by outcome (acquired, rejected) when the session semaphore is granted or full." ); describe_counter!( "gitssh_exec_total", "SSH exec requests partitioned by git service and outcome (success, error)." ); describe_counter!( "gitssh_subprocess_total", "Git subprocess runs partitioned by git service and status (success, error)." ); describe_histogram!( "gitssh_subprocess_duration_seconds", Unit::Seconds, "Duration of git subprocess runs." ); } pub(crate) fn outcome(ok: bool) -> &'static str { if ok { OUTCOME_SUCCESS } else { OUTCOME_ERROR } } pub(crate) fn record_session(acquired: bool) { ensure_described(); counter!( "gitssh_sessions_total", "outcome" => if acquired { OUTCOME_ACQUIRED } else { OUTCOME_REJECTED } ) .increment(1); } pub(crate) fn record_exec(service: &'static str, ok: bool) { ensure_described(); counter!( "gitssh_exec_total", "service" => service, "outcome" => outcome(ok) ) .increment(1); } pub(crate) fn record_subprocess(service: &'static str, ok: bool) { ensure_described(); counter!( "gitssh_subprocess_total", "service" => service, "status" => outcome(ok) ) .increment(1); } pub(crate) struct SubprocessTimer { start: Instant, } impl SubprocessTimer { pub(crate) fn start() -> Self { ensure_described(); Self { start: Instant::now(), } } } impl Drop for SubprocessTimer { fn drop(&mut self) { histogram!("gitssh_subprocess_duration_seconds").record(self.start.elapsed()); } }