metrics_observer_json/
lib.rs1#![deny(missing_docs)]
35use hdrhistogram::Histogram;
36use metrics_core::{Builder, Drain, Key, Label, Observer};
37use metrics_util::{parse_quantiles, MetricsTree, Quantile};
38use std::collections::HashMap;
39
40pub struct JsonBuilder {
42 quantiles: Vec<Quantile>,
43 pretty: bool,
44}
45
46impl JsonBuilder {
47 pub fn new() -> Self {
49 let quantiles = parse_quantiles(&[0.0, 0.5, 0.9, 0.95, 0.99, 0.999, 1.0]);
50
51 Self {
52 quantiles,
53 pretty: false,
54 }
55 }
56
57 pub fn set_quantiles(mut self, quantiles: &[f64]) -> Self {
64 self.quantiles = parse_quantiles(quantiles);
65 self
66 }
67
68 pub fn set_pretty_json(mut self, pretty: bool) -> Self {
75 self.pretty = pretty;
76 self
77 }
78}
79
80impl Builder for JsonBuilder {
81 type Output = JsonObserver;
82
83 fn build(&self) -> Self::Output {
84 JsonObserver {
85 quantiles: self.quantiles.clone(),
86 pretty: self.pretty,
87 tree: MetricsTree::default(),
88 histos: HashMap::new(),
89 }
90 }
91}
92
93impl Default for JsonBuilder {
94 fn default() -> Self {
95 Self::new()
96 }
97}
98
99pub struct JsonObserver {
101 pub(crate) quantiles: Vec<Quantile>,
102 pub(crate) pretty: bool,
103 pub(crate) tree: MetricsTree,
104 pub(crate) histos: HashMap<Key, Histogram<u64>>,
105}
106
107impl Observer for JsonObserver {
108 fn observe_counter(&mut self, key: Key, value: u64) {
109 let (levels, name) = key_to_parts(key);
110 self.tree.insert_value(levels, name, value);
111 }
112
113 fn observe_gauge(&mut self, key: Key, value: i64) {
114 let (levels, name) = key_to_parts(key);
115 self.tree.insert_value(levels, name, value);
116 }
117
118 fn observe_histogram(&mut self, key: Key, values: &[u64]) {
119 let entry = self
120 .histos
121 .entry(key)
122 .or_insert_with(|| Histogram::<u64>::new(3).expect("failed to create histogram"));
123
124 for value in values {
125 entry
126 .record(*value)
127 .expect("failed to observe histogram value");
128 }
129 }
130}
131
132impl Drain<String> for JsonObserver {
133 fn drain(&mut self) -> String {
134 for (key, h) in self.histos.drain() {
135 let (levels, name) = key_to_parts(key);
136 let values = hist_to_values(name, h.clone(), &self.quantiles);
137 self.tree.insert_values(levels, values);
138 }
139
140 let result = if self.pretty {
141 serde_json::to_string_pretty(&self.tree)
142 } else {
143 serde_json::to_string(&self.tree)
144 };
145 let rendered = result.expect("failed to render json output");
146 self.tree.clear();
147 rendered
148 }
149}
150
151fn key_to_parts(key: Key) -> (Vec<String>, String) {
152 let (name, labels) = key.into_parts();
153 let mut parts = name.split('.').map(ToOwned::to_owned).collect::<Vec<_>>();
154 let name = parts.pop().expect("name didn't have a single part");
155
156 let labels = labels
157 .into_iter()
158 .map(Label::into_parts)
159 .map(|(k, v)| format!("{}=\"{}\"", k, v))
160 .collect::<Vec<_>>()
161 .join(",");
162 let label = if labels.is_empty() {
163 String::new()
164 } else {
165 format!("{{{}}}", labels)
166 };
167
168 let fname = format!("{}{}", name, label);
169
170 (parts, fname)
171}
172
173fn hist_to_values(
174 name: String,
175 hist: Histogram<u64>,
176 quantiles: &[Quantile],
177) -> Vec<(String, u64)> {
178 let mut values = Vec::new();
179
180 values.push((format!("{} count", name), hist.len()));
181 for quantile in quantiles {
182 let value = hist.value_at_quantile(quantile.value());
183 values.push((format!("{} {}", name, quantile.label()), value));
184 }
185
186 values
187}