Skip to main content

rs_zero/observability/metrics/
http.rs

1use std::{collections::BTreeMap, fmt::Write};
2
3use super::{DurationMetricValue, escape_label, write_duration_metric};
4
5/// Low-cardinality labels recorded for each HTTP request.
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
7pub struct HttpMetricLabels {
8    /// HTTP method.
9    pub method: String,
10    /// Route pattern or explicit route name. Raw request paths should not be used.
11    pub route: String,
12    /// HTTP status code.
13    pub status: u16,
14}
15
16impl HttpMetricLabels {
17    /// Creates a label set for one HTTP request.
18    pub fn new(method: impl Into<String>, route: impl Into<String>, status: u16) -> Self {
19        Self {
20            method: method.into(),
21            route: route.into(),
22            status,
23        }
24    }
25}
26
27pub(crate) fn render(
28    output: &mut String,
29    metrics: &BTreeMap<HttpMetricLabels, DurationMetricValue>,
30    in_flight: i64,
31) {
32    output.push_str("# HELP rs_zero_http_requests_total Total number of HTTP requests.\n");
33    output.push_str("# TYPE rs_zero_http_requests_total counter\n");
34    for (labels, value) in metrics {
35        write!(output, "rs_zero_http_requests_total{{").ok();
36        write_labels(output, labels, None);
37        writeln!(output, "}} {}", value.count).ok();
38    }
39
40    output.push_str("# HELP rs_zero_http_request_duration_seconds HTTP request duration.\n");
41    output.push_str("# TYPE rs_zero_http_request_duration_seconds histogram\n");
42    for (labels, value) in metrics {
43        write_duration_metric(
44            output,
45            "rs_zero_http_request_duration_seconds",
46            labels,
47            value,
48            write_labels,
49        );
50    }
51
52    output.push_str("# HELP rs_zero_http_requests_in_flight Current in-flight HTTP requests.\n");
53    output.push_str("# TYPE rs_zero_http_requests_in_flight gauge\n");
54    writeln!(output, "rs_zero_http_requests_in_flight {in_flight}").ok();
55}
56
57fn write_labels(output: &mut String, labels: &HttpMetricLabels, le: Option<&str>) {
58    write!(
59        output,
60        "method=\"{}\",route=\"{}\",status=\"{}\"",
61        escape_label(&labels.method),
62        escape_label(&labels.route),
63        labels.status
64    )
65    .ok();
66    if let Some(le) = le {
67        write!(output, ",le=\"{}\"", escape_label(le)).ok();
68    }
69}