rs_zero/observability/metrics/
rpc.rs1use std::{collections::BTreeMap, fmt::Write};
2
3use super::{DurationMetricValue, escape_label, write_duration_metric};
4
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
7pub struct RpcMetricLabels {
8 pub service: String,
10 pub method: String,
12 pub code: String,
14}
15
16impl RpcMetricLabels {
17 pub fn new(
19 service: impl Into<String>,
20 method: impl Into<String>,
21 code: impl Into<String>,
22 ) -> Self {
23 Self {
24 service: service.into(),
25 method: method.into(),
26 code: code.into(),
27 }
28 }
29}
30
31pub(crate) fn render(
32 output: &mut String,
33 metrics: &BTreeMap<RpcMetricLabels, DurationMetricValue>,
34) {
35 output.push_str("# HELP rs_zero_rpc_requests_total Total number of gRPC requests.\n");
36 output.push_str("# TYPE rs_zero_rpc_requests_total counter\n");
37 for (labels, value) in metrics {
38 write!(output, "rs_zero_rpc_requests_total{{").ok();
39 write_labels(output, labels, None);
40 writeln!(output, "}} {}", value.count).ok();
41 }
42
43 output.push_str("# HELP rs_zero_rpc_request_duration_seconds gRPC request duration.\n");
44 output.push_str("# TYPE rs_zero_rpc_request_duration_seconds histogram\n");
45 for (labels, value) in metrics {
46 write_duration_metric(
47 output,
48 "rs_zero_rpc_request_duration_seconds",
49 labels,
50 value,
51 write_labels,
52 );
53 }
54}
55
56fn write_labels(output: &mut String, labels: &RpcMetricLabels, le: Option<&str>) {
57 write!(
58 output,
59 "service=\"{}\",method=\"{}\",code=\"{}\"",
60 escape_label(&labels.service),
61 escape_label(&labels.method),
62 escape_label(&labels.code)
63 )
64 .ok();
65 if let Some(le) = le {
66 write!(output, ",le=\"{}\"", escape_label(le)).ok();
67 }
68}