open_chess_server/
metrics.rs1use prometheus::{IntCounter, IntCounterVec, IntGaugeVec, Opts, Registry};
4
5#[derive(Clone)]
6pub struct Metrics {
7 pub registry: Registry,
8 pub moves: IntCounter,
9 pub games_started: IntCounter,
10 pub games_finished: IntCounterVec,
11 pub challenges: IntCounterVec,
12 pub streams: IntGaugeVec,
13 pub analysed: IntCounterVec,
14}
15
16impl Metrics {
17 pub fn new() -> Metrics {
18 let registry = Registry::new_custom(Some("chess".into()), None).expect("valid prefix");
19 let moves = IntCounter::new("moves_total", "Moves played").expect("valid metric");
20 let games_started = IntCounter::new("games_started_total", "Games started").expect("valid metric");
21 let games_finished =
22 IntCounterVec::new(Opts::new("games_finished_total", "Games finished, by status"), &["status"])
23 .expect("valid metric");
24 let challenges =
25 IntCounterVec::new(Opts::new("challenges_total", "Challenges, by outcome"), &["outcome"])
26 .expect("valid metric");
27 let streams =
28 IntGaugeVec::new(Opts::new("streams_open", "Open NDJSON streams on this replica"), &["kind"])
29 .expect("valid metric");
30 let analysed = IntCounterVec::new(
31 Opts::new("fairplay_sides_analysed_total", "Players' games screened"),
32 &["flagged"],
33 )
34 .expect("valid metric");
35 for c in [
36 Box::new(moves.clone()) as Box<dyn prometheus::core::Collector>,
37 Box::new(games_started.clone()),
38 Box::new(games_finished.clone()),
39 Box::new(challenges.clone()),
40 Box::new(streams.clone()),
41 Box::new(analysed.clone()),
42 ] {
43 registry.register(c).expect("unique metric");
44 }
45 Metrics { registry, moves, games_started, games_finished, challenges, streams, analysed }
46 }
47
48 pub fn render(&self) -> String {
49 use prometheus::Encoder;
50 let mut buf = Vec::new();
51 let _ = prometheus::TextEncoder::new().encode(&self.registry.gather(), &mut buf);
52 String::from_utf8(buf).unwrap_or_default()
53 }
54}
55
56impl Default for Metrics {
57 fn default() -> Self {
58 Metrics::new()
59 }
60}
61
62pub struct StreamGuard(prometheus::IntGauge);
64
65impl StreamGuard {
66 pub fn new(m: &Metrics, kind: &str) -> StreamGuard {
67 let g = m.streams.with_label_values(&[kind]);
68 g.inc();
69 StreamGuard(g)
70 }
71}
72
73impl Drop for StreamGuard {
74 fn drop(&mut self) {
75 self.0.dec();
76 }
77}