Skip to content

Commit b04d43f

Browse files
committed
Initial native histogram support
1 parent 1ae7e90 commit b04d43f

6 files changed

Lines changed: 568 additions & 0 deletions

File tree

src/encoding.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,37 @@ impl MetricEncoder<'_> {
198198
)
199199
}
200200

201+
/// Encode a native histogram.
202+
pub fn encode_native_histogram(
203+
&mut self,
204+
sum: f64,
205+
count: u64,
206+
schema: i32,
207+
zero_threshold: f64,
208+
zero_count: u64,
209+
negative_spans: &[(i32, u32)],
210+
negative_deltas: &[i64],
211+
positive_spans: &[(i32, u32)],
212+
positive_deltas: &[i64],
213+
) -> Result<(), std::fmt::Error> {
214+
for_both_mut!(
215+
self,
216+
MetricEncoderInner,
217+
e,
218+
e.encode_native_histogram(
219+
sum,
220+
count,
221+
schema,
222+
zero_threshold,
223+
zero_count,
224+
negative_spans,
225+
negative_deltas,
226+
positive_spans,
227+
positive_deltas,
228+
)
229+
)
230+
}
231+
201232
/// Encode a metric family.
202233
pub fn encode_family<'s, S: EncodeLabelSet>(
203234
&'s mut self,

src/encoding/proto/openmetrics_data_model.proto

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,29 @@ message HistogramValue {
140140
// Optional.
141141
repeated Bucket buckets = 5;
142142

143+
// Everything below here is for native histograms.
144+
// Schema for standard exponential buckets (currently -4..8).
145+
sint32 schema = 6;
146+
147+
// Breadth of the zero bucket.
148+
double zero_threshold = 7;
149+
150+
// Count in zero bucket.
151+
uint64 zero_count = 8;
152+
153+
// Negative buckets for the native histogram.
154+
repeated BucketSpan negative_span = 9;
155+
repeated sint64 negative_delta = 10;
156+
repeated double negative_count = 11;
157+
158+
// Positive buckets for the native histogram.
159+
repeated BucketSpan positive_span = 12;
160+
repeated sint64 positive_delta = 13;
161+
repeated double positive_count = 14;
162+
163+
// Native histogram exemplars. Must carry a timestamp.
164+
repeated Exemplar exemplars = 15;
165+
143166
// Bucket is the number of values for a bucket in the histogram
144167
// with an optional exemplar.
145168
message Bucket {
@@ -152,6 +175,14 @@ message HistogramValue {
152175
// Optional.
153176
Exemplar exemplar = 3;
154177
}
178+
179+
// Consecutive run of sparse bucket indexes.
180+
message BucketSpan {
181+
// Gap to previous span, or starting point for first span.
182+
sint32 offset = 1;
183+
// Number of consecutive buckets in the span.
184+
uint32 length = 2;
185+
}
155186
}
156187

157188
message Exemplar {

src/encoding/protobuf.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,68 @@ impl MetricEncoder<'_> {
288288

289289
Ok(())
290290
}
291+
292+
pub fn encode_native_histogram(
293+
&mut self,
294+
sum: f64,
295+
count: u64,
296+
schema: i32,
297+
zero_threshold: f64,
298+
zero_count: u64,
299+
negative_spans: &[(i32, u32)],
300+
negative_deltas: &[i64],
301+
positive_spans: &[(i32, u32)],
302+
positive_deltas: &[i64],
303+
) -> Result<(), std::fmt::Error> {
304+
let negative_span = negative_spans
305+
.iter()
306+
.map(
307+
|(offset, length)| openmetrics_data_model::histogram_value::BucketSpan {
308+
offset: *offset,
309+
length: *length,
310+
},
311+
)
312+
.collect();
313+
314+
let positive_span = positive_spans
315+
.iter()
316+
.map(
317+
|(offset, length)| openmetrics_data_model::histogram_value::BucketSpan {
318+
offset: *offset,
319+
length: *length,
320+
},
321+
)
322+
.collect();
323+
324+
self.family.push(openmetrics_data_model::Metric {
325+
labels: self.labels.clone(),
326+
metric_points: vec![openmetrics_data_model::MetricPoint {
327+
value: Some(openmetrics_data_model::metric_point::Value::HistogramValue(
328+
openmetrics_data_model::HistogramValue {
329+
count,
330+
created: None,
331+
buckets: Vec::new(),
332+
sum: Some(openmetrics_data_model::histogram_value::Sum::DoubleValue(
333+
sum,
334+
)),
335+
schema,
336+
zero_threshold,
337+
zero_count,
338+
negative_span,
339+
negative_delta: negative_deltas.to_vec(),
340+
negative_count: Vec::new(),
341+
positive_span,
342+
positive_delta: positive_deltas.to_vec(),
343+
positive_count: Vec::new(),
344+
exemplars: Vec::new(),
345+
},
346+
)),
347+
..Default::default()
348+
}],
349+
});
350+
351+
Ok(())
352+
}
291353
}
292354

293355
impl<S: EncodeLabelSet, V: EncodeExemplarValue> TryFrom<&Exemplar<S, V>>

src/encoding/text.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,23 @@ impl MetricEncoder<'_> {
444444
Ok(())
445445
}
446446

447+
pub fn encode_native_histogram(
448+
&mut self,
449+
_sum: f64,
450+
_count: u64,
451+
_schema: i32,
452+
_zero_threshold: f64,
453+
_zero_count: u64,
454+
_negative_spans: &[(i32, u32)],
455+
_negative_deltas: &[i64],
456+
_positive_spans: &[(i32, u32)],
457+
_positive_deltas: &[i64],
458+
) -> Result<(), std::fmt::Error> {
459+
// Native histogram text exposition is not defined. Treat this as a
460+
// no-op to avoid failing an entire scrape with mixed metric families.
461+
Ok(())
462+
}
463+
447464
/// Encode an exemplar for the given metric.
448465
fn encode_exemplar<S: EncodeLabelSet, V: EncodeExemplarValue>(
449466
&mut self,

src/metrics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod family;
66
pub mod gauge;
77
pub mod histogram;
88
pub mod info;
9+
pub mod native_histogram;
910

1011
/// A metric that is aware of its Open Metrics metric type.
1112
pub trait TypedMetric {

0 commit comments

Comments
 (0)