Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions benches/encoding/proto.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
// Benchmark inspired by
// https://github.com/tikv/rust-prometheus/blob/ab1ca7285d3463504381a5025ae1951e020d6796/benches/text_encoder.rs:write

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use prometheus_client::encoding::prometheus_protobuf;
use prometheus_client::metrics::counter::Counter;
use prometheus_client::metrics::family::Family;
use prometheus_client::metrics::histogram::{exponential_buckets, Histogram};
use prometheus_client::registry::Registry;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use prometheus_client::{
encoding::prometheus_protobuf,
metrics::{
counter::Counter,
family::Family,
histogram::{Histogram, exponential_buckets},
},
registry::Registry,
};
use prometheus_client_derive_encode::{EncodeLabelSet, EncodeLabelValue};

pub fn proto(c: &mut Criterion) {
c.bench_function("encode", |b| {
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug, PartialOrd, Ord)]
struct CounterLabels {
path: String,
method: Method,
some_number: u64,
}

#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug, PartialOrd, Ord)]
enum Method {
Get,
#[allow(dead_code)]
Put,
}

#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug, PartialOrd, Ord)]
struct HistogramLabels {
region: Region,
}

#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug, PartialOrd, Ord)]
enum Region {
Africa,
#[allow(dead_code)]
Expand Down
6 changes: 3 additions & 3 deletions benches/encoding/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ use std::fmt::Write;

pub fn text(c: &mut Criterion) {
c.bench_function("encode", |b| {
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
#[derive(Clone, Ord, PartialOrd, PartialEq, Eq, EncodeLabelSet, Debug)]
struct Labels {
method: Method,
status: Status,
some_number: u64,
}

#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
#[derive(Clone, Ord, PartialOrd, PartialEq, Eq, EncodeLabelValue, Debug)]
enum Method {
Get,
#[allow(dead_code)]
Put,
}

#[derive(Clone, Hash, PartialEq, Eq, Debug)]
#[derive(Clone, Ord, PartialOrd, PartialEq, Eq, Debug)]
enum Status {
Two,
#[allow(dead_code)]
Expand Down
6 changes: 3 additions & 3 deletions benches/family.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ pub fn family(c: &mut Criterion) {
});

c.bench_function("counter family with custom type label set", |b| {
#[derive(Clone, Hash, PartialEq, Eq)]
#[derive(Clone, Ord, PartialOrd, PartialEq, Eq)]
struct Labels {
method: Method,
status: Status,
}

#[derive(Clone, Hash, PartialEq, Eq)]
#[derive(Clone, Ord, PartialOrd, PartialEq, Eq)]
enum Method {
Get,
#[allow(dead_code)]
Put,
}

#[derive(Clone, Hash, PartialEq, Eq)]
#[derive(Clone, Ord, PartialOrd, PartialEq, Eq)]
enum Status {
Two,
#[allow(dead_code)]
Expand Down
32 changes: 16 additions & 16 deletions derive-encode/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use std::sync::Arc;

use prometheus_client::encoding::text::encode;
use prometheus_client::encoding::{EncodeLabelSet, EncodeLabelValue};
use prometheus_client::metrics::counter::Counter;
use prometheus_client::metrics::family::Family;
use prometheus_client::registry::Registry;
use prometheus_client::{
encoding::{EncodeLabelSet, EncodeLabelValue, text::encode},
metrics::{counter::Counter, family::Family},
registry::Registry,
};

#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug, PartialOrd, Ord)]
struct Labels {
method: Method,
path: String,
}

#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug, PartialOrd, Ord)]
enum Method {
Get,
#[allow(dead_code)]
Expand Down Expand Up @@ -47,11 +47,11 @@ fn basic_flow() {

mod protobuf {
use crate::{Labels, Method};
use prometheus_client::encoding::prometheus_protobuf::encode;
use prometheus_client::encoding::prometheus_protobuf::prometheus_data_model;
use prometheus_client::metrics::counter::Counter;
use prometheus_client::metrics::family::Family;
use prometheus_client::registry::Registry;
use prometheus_client::{
encoding::prometheus_protobuf::{encode, prometheus_data_model},
metrics::{counter::Counter, family::Family},
registry::Registry,
};

#[test]
fn structs() {
Expand Down Expand Up @@ -106,7 +106,7 @@ mod protobuf {

#[test]
fn remap_keyword_identifiers() {
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug, PartialOrd, Ord)]
struct Labels {
// `r#type` is problematic as `r#` is not a valid OpenMetrics label name
// but one needs to use keyword identifier syntax (aka. raw identifiers)
Expand Down Expand Up @@ -137,7 +137,7 @@ fn remap_keyword_identifiers() {

#[test]
fn arc_string() {
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug, PartialOrd, Ord)]
struct Labels {
client_id: Arc<String>,
}
Expand Down Expand Up @@ -167,12 +167,12 @@ fn arc_string() {

#[test]
fn flatten() {
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug, PartialOrd, Ord)]
struct CommonLabels {
a: u64,
b: u64,
}
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug, PartialOrd, Ord)]
struct Labels {
unique: u64,
#[prometheus(flatten)]
Expand Down
4 changes: 2 additions & 2 deletions examples/actix-web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use prometheus_client::metrics::counter::Counter;
use prometheus_client::metrics::family::Family;
use prometheus_client::registry::Registry;

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EncodeLabelValue)]
pub enum Method {
Get,
Post,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EncodeLabelSet)]
pub struct MethodLabels {
pub method: Method,
}
Expand Down
4 changes: 2 additions & 2 deletions examples/axum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ use prometheus_client_derive_encode::{EncodeLabelSet, EncodeLabelValue};
use std::sync::Arc;
use tokio::sync::Mutex;

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)]
#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, EncodeLabelValue)]
pub enum Method {
Get,
Post,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
#[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq, EncodeLabelSet)]
pub struct MethodLabels {
pub method: Method,
}
Expand Down
4 changes: 2 additions & 2 deletions examples/tide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ async fn main() -> std::result::Result<(), std::io::Error> {
Ok(())
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EncodeLabelSet)]
struct Labels {
method: Method,
path: String,
}

#[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EncodeLabelValue)]
enum Method {
Get,
Put,
Expand Down
97 changes: 74 additions & 23 deletions src/encoding/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,15 @@
//! assert_eq!(expected_msg, buffer);
//! ```

use crate::encoding::{
EncodeExemplarTime, EncodeExemplarValue, EncodeLabelSet, NativeHistogram, NoLabelSet,
use crate::{
encoding::{
EncodeExemplarTime, EncodeExemplarValue, EncodeLabelSet, NativeHistogram, NoLabelSet,
},
metrics::{MetricType, exemplar::Exemplar},
registry::{Prefix, Registry, Unit},
};
use crate::metrics::exemplar::Exemplar;
use crate::metrics::MetricType;
use crate::registry::{Prefix, Registry, Unit};

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::Write;
use std::{borrow::Cow, collections::HashMap, fmt::Write};

/// Encode both the metrics registered with the provided [`Registry`] and the
/// EOF marker into the provided [`Write`]r using the OpenMetrics text format.
Expand Down Expand Up @@ -759,17 +758,21 @@ impl std::fmt::Write for LabelValueEncoder<'_> {
#[cfg(test)]
mod tests {
use super::*;
use crate::metrics::exemplar::HistogramWithExemplars;
use crate::metrics::family::Family;
use crate::metrics::gauge::Gauge;
use crate::metrics::histogram::{exponential_buckets, Histogram, NativeHistogramConfig};
use crate::metrics::info::Info;
use crate::metrics::{counter::Counter, exemplar::CounterWithExemplar};
use crate::metrics::{
counter::Counter,
exemplar::{CounterWithExemplar, HistogramWithExemplars},
family::Family,
gauge::Gauge,
histogram::{Histogram, NativeHistogramConfig, exponential_buckets},
info::Info,
};
use pyo3::{prelude::*, types::PyModule};
use std::borrow::Cow;
use std::fmt::Error;
use std::sync::atomic::{AtomicI32, AtomicU32};
use std::time::{SystemTime, UNIX_EPOCH};
use std::{
borrow::Cow,
fmt::Error,
sync::atomic::{AtomicI32, AtomicU32},
time::{SystemTime, UNIX_EPOCH},
};

#[test]
fn encode_counter() {
Expand Down Expand Up @@ -916,8 +919,7 @@ mod tests {

encode(&mut encoded, &registry).unwrap();

let expected = "# HELP my_prefix_my_counter_family My counter family.\n"
.to_owned()
let expected = "# HELP my_prefix_my_counter_family My counter family.\n".to_owned()
+ "# TYPE my_prefix_my_counter_family counter\n"
+ "my_prefix_my_counter_family_total{my_key=\"my_value\",method=\"GET\",status=\"200\"} 1\n"
+ "# EOF\n";
Expand Down Expand Up @@ -1020,7 +1022,7 @@ mod tests {
Family::new_with_constructor(|| Histogram::new(exponential_buckets(1.0, 2.0, 10)));
registry.register("my_histogram", "My histogram", family.clone());

#[derive(Eq, PartialEq, Hash, Debug, Clone)]
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)]
struct EmptyLabels {}

impl EncodeLabelSet for EmptyLabels {
Expand Down Expand Up @@ -1210,7 +1212,7 @@ mod tests {

#[test]
fn label_sets_can_be_composed() {
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
struct Color(&'static str);
impl EncodeLabelSet for Color {
fn encode(
Expand All @@ -1225,7 +1227,7 @@ mod tests {
}
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
struct Size(&'static str);
impl EncodeLabelSet for Size {
fn encode(
Expand Down Expand Up @@ -1373,4 +1375,53 @@ def parse(input):
+ "# EOF\n";
assert_eq!(expected, encoded);
}

#[test]
fn metrics_are_sorted_by_registration_order() {
let mut registry = Registry::default();
let counter: Counter = Counter::default();
let another_counter: Counter = Counter::default();
registry.register("my_counter", "My counter", counter);
registry.register("another_counter", "Another counter", another_counter);

let mut encoded = String::new();
encode(&mut encoded, &registry).unwrap();

let expected = "# HELP my_counter My counter.\n".to_owned()
+ "# TYPE my_counter counter\n"
+ "my_counter_total 0\n"
+ "# HELP another_counter Another counter.\n"
+ "# TYPE another_counter counter\n"
+ "another_counter_total 0\n"
+ "# EOF\n";
assert_eq!(expected, encoded);
}

#[test]
fn metric_family_is_sorted_lexicographically() {
let mut registry = Registry::default();
let gauge = Family::<Vec<(String, String)>, Gauge>::default();
registry.register("my_gauge", "My gauge", gauge.clone());

gauge
.get_or_create(&vec![("label".to_string(), "0".to_string())])
.set(0);
gauge
.get_or_create(&vec![("label".to_string(), "2".to_string())])
.set(2);
gauge
.get_or_create(&vec![("label".to_string(), "1".to_string())])
.set(1);

let mut encoded = String::new();
encode(&mut encoded, &registry).unwrap();

let expected = "# HELP my_gauge My gauge.\n".to_owned()
+ "# TYPE my_gauge gauge\n"
+ "my_gauge{label=\"0\"} 0\n"
+ "my_gauge{label=\"1\"} 1\n"
+ "my_gauge{label=\"2\"} 2\n"
+ "# EOF\n";
assert_eq!(expected, encoded);
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@
//! //
//! // You could as well use `(String, String)` to represent a label set,
//! // instead of the custom type below.
//! #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelSet)]
//! #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EncodeLabelSet)]
//! struct Labels {
//! // Use your own enum types to represent label values.
//! method: Method,
//! // Or just a plain string.
//! path: String,
//! };
//!
//! #[derive(Clone, Debug, Hash, PartialEq, Eq, EncodeLabelValue)]
//! #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, EncodeLabelValue)]
//! enum Method {
//! GET,
//! PUT,
Expand Down
Loading
Loading