rs_zero/observability/metrics/
redis.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 RedisMetricLabels {
8 pub command: String,
10 pub shard: String,
12 pub result: String,
14}
15
16impl RedisMetricLabels {
17 pub fn new(
19 command: impl Into<String>,
20 shard: impl Into<String>,
21 result: impl Into<String>,
22 ) -> Self {
23 Self {
24 command: command.into(),
25 shard: shard.into(),
26 result: result.into(),
27 }
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
33pub struct RedisEventLabels {
34 pub event: String,
36 pub shard: String,
38 pub result: String,
40}
41
42impl RedisEventLabels {
43 pub fn new(
45 event: impl Into<String>,
46 shard: impl Into<String>,
47 result: impl Into<String>,
48 ) -> Self {
49 Self {
50 event: event.into(),
51 shard: shard.into(),
52 result: result.into(),
53 }
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
59pub struct RedisDegradationLabels {
60 pub operation: String,
62 pub action: String,
64 pub shard: String,
66}
67
68impl RedisDegradationLabels {
69 pub fn new(
71 operation: impl Into<String>,
72 action: impl Into<String>,
73 shard: impl Into<String>,
74 ) -> Self {
75 Self {
76 operation: operation.into(),
77 action: action.into(),
78 shard: shard.into(),
79 }
80 }
81}
82
83pub(crate) fn render(
84 output: &mut String,
85 metrics: &BTreeMap<RedisMetricLabels, DurationMetricValue>,
86 events: &BTreeMap<RedisEventLabels, u64>,
87 degradations: &BTreeMap<RedisDegradationLabels, u64>,
88) {
89 output.push_str("# HELP rs_zero_redis_commands_total Total number of Redis commands.\n");
90 output.push_str("# TYPE rs_zero_redis_commands_total counter\n");
91 for (labels, value) in metrics {
92 write!(output, "rs_zero_redis_commands_total{{").ok();
93 write_labels(output, labels, None);
94 writeln!(output, "}} {}", value.count).ok();
95 }
96
97 output.push_str(
98 "# HELP rs_zero_redis_command_errors_total Total number of failed Redis commands.\n",
99 );
100 output.push_str("# TYPE rs_zero_redis_command_errors_total counter\n");
101 for (labels, value) in metrics
102 .iter()
103 .filter(|(labels, _)| labels.result != "success")
104 {
105 write!(output, "rs_zero_redis_command_errors_total{{").ok();
106 write_labels(output, labels, None);
107 writeln!(output, "}} {}", value.count).ok();
108 }
109
110 output.push_str("# HELP rs_zero_redis_command_duration_seconds Redis command duration.\n");
111 output.push_str("# TYPE rs_zero_redis_command_duration_seconds histogram\n");
112 for (labels, value) in metrics {
113 write_duration_metric(
114 output,
115 "rs_zero_redis_command_duration_seconds",
116 labels,
117 value,
118 write_labels,
119 );
120 }
121
122 output.push_str("# HELP rs_zero_redis_events_total Total number of Redis pool, redirect, script and degradation events.\n");
123 output.push_str("# TYPE rs_zero_redis_events_total counter\n");
124 for (labels, value) in events {
125 write!(output, "rs_zero_redis_events_total{{").ok();
126 write_event_labels(output, labels);
127 writeln!(output, "}} {}", value).ok();
128 }
129
130 output.push_str("# HELP rs_zero_redis_degradations_total Total number of explicitly degraded Redis operations.\n");
131 output.push_str("# TYPE rs_zero_redis_degradations_total counter\n");
132 for (labels, value) in degradations {
133 write!(output, "rs_zero_redis_degradations_total{{").ok();
134 write_degradation_labels(output, labels);
135 writeln!(output, "}} {}", value).ok();
136 }
137}
138
139fn write_labels(output: &mut String, labels: &RedisMetricLabels, le: Option<&str>) {
140 write!(
141 output,
142 "command=\"{}\",shard=\"{}\",result=\"{}\"",
143 escape_label(&labels.command),
144 escape_label(&labels.shard),
145 escape_label(&labels.result)
146 )
147 .ok();
148 if let Some(le) = le {
149 write!(output, ",le=\"{}\"", escape_label(le)).ok();
150 }
151}
152
153fn write_event_labels(output: &mut String, labels: &RedisEventLabels) {
154 write!(
155 output,
156 "event=\"{}\",shard=\"{}\",result=\"{}\"",
157 escape_label(&labels.event),
158 escape_label(&labels.shard),
159 escape_label(&labels.result)
160 )
161 .ok();
162}
163
164fn write_degradation_labels(output: &mut String, labels: &RedisDegradationLabels) {
165 write!(
166 output,
167 "operation=\"{}\",action=\"{}\",shard=\"{}\"",
168 escape_label(&labels.operation),
169 escape_label(&labels.action),
170 escape_label(&labels.shard)
171 )
172 .ok();
173}