Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/: Adopt serde style encoding #105

Merged
merged 1 commit into from Dec 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Expand Up @@ -16,11 +16,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Move`Encode` trait from `prometheus_client::encoding::text` to `prometheus_client::encoding`. See [PR 83].
- Always use dynamic dispatch on `Registry`, i.e. remove generic type parameter `M` from `Registry`. See [PR 105].
- Refactor encoding. See [PR 105].
- Introducing separate traits to encode
- value (e.g. `EncodeCounterValue`)
- label set (`EncodeLabelSet`), derivable for structs via `prometheus-client-derive-encode`
- label (`EncodeLabel`)
- label key (`EncodeLabelKey`)
- label value (`EncodeLabelValue`), derivable for enums via `prometheus-client-derive-encode`
- Encode as UTF-8 strings, not bytes. I.e. use `std::fmt::Write` instead of `std::io::Write`.
- Use signed integers for `Gauge` for compliance with OpenMetrics protobuf
format. See [PR 105].

[PR 83]: https://github.com/prometheus/client_rust/pull/83
[PR 85]: https://github.com/prometheus/client_rust/pull/85
[PR 96]: https://github.com/prometheus/client_rust/pull/96
[PR 105]: https://github.com/prometheus/client_rust/pull/105

## [0.18.1]

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Expand Up @@ -11,7 +11,8 @@ homepage = "https://github.com/prometheus/client_rust"
documentation = "https://docs.rs/prometheus-client"

[features]
protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build", "dep:void", "prometheus-client-derive-encode/protobuf"]
default = []
protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build"]

[workspace]
members = ["derive-encode"]
Expand All @@ -23,7 +24,6 @@ parking_lot = "0.12"
prometheus-client-derive-encode = { version = "0.3.0", path = "derive-encode" }
prost = { version = "0.11.0", optional = true }
prost-types = { version = "0.11.0", optional = true }
void = { version = "1.0", optional = true }

[dev-dependencies]
async-std = { version = "1", features = ["attributes"] }
Expand Down
46 changes: 22 additions & 24 deletions benches/encoding/proto.rs
Expand Up @@ -2,82 +2,80 @@
// 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::proto::{encode, EncodeMetric};
use prometheus_client::encoding::Encode;
use prometheus_client::encoding::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 std::fmt::{Display, Formatter};
use prometheus_client_derive_encode::{EncodeLabelSet, EncodeLabelValue};

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

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

impl Display for Method {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Method::Get => write!(f, "Get"),
Method::Put => write!(f, "Put"),
}
}
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
struct HistogramLabels {
region: Region,
}

#[derive(Clone, Hash, PartialEq, Eq, Encode)]
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
enum Region {
Africa,
#[allow(dead_code)]
Asia,
}

let mut registry = Registry::<Box<dyn EncodeMetric>>::default();
let mut registry = Registry::default();

for i in 0..100 {
let counter_family = Family::<Labels, Counter>::default();
let histogram_family = Family::<Region, Histogram>::new_with_constructor(|| {
Histogram::new(exponential_buckets(1.0, 2.0, 10))
});
let counter_family = Family::<CounterLabels, Counter>::default();
let histogram_family =
Family::<HistogramLabels, Histogram>::new_with_constructor(|| {
Histogram::new(exponential_buckets(1.0, 2.0, 10))
});

registry.register(
format!("my_counter{}", i),
"My counter",
Box::new(counter_family.clone()),
counter_family.clone(),
);
registry.register(
format!("my_histogram{}", i),
"My histogram",
Box::new(histogram_family.clone()),
histogram_family.clone(),
);

for j in 0_u32..100 {
counter_family
.get_or_create(&Labels {
.get_or_create(&CounterLabels {
path: format!("/path/{}", i),
method: Method::Get,
some_number: j.into(),
})
.inc();

histogram_family
.get_or_create(&Region::Africa)
.get_or_create(&HistogramLabels {
region: Region::Africa,
})
.observe(j.into());
}
}

b.iter(|| {
let metric_set = encode(&registry);
let metric_set = protobuf::encode(&registry).unwrap();
black_box(metric_set);
})
});
Expand Down
48 changes: 16 additions & 32 deletions benches/encoding/text.rs
@@ -1,31 +1,30 @@
// Benchmark inspired by https://github.com/tikv/rust-prometheus/blob/ab1ca7285d3463504381a5025ae1951e020d6796/benches/text_encoder.rs

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use prometheus_client::encoding::text::{encode, EncodeMetric};
use prometheus_client::encoding::Encode;
use prometheus_client::encoding::{self, EncodeLabelSet, EncodeLabelValue, LabelValueEncoder};
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 std::io::Write;
use std::fmt::Write;

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

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

#[derive(Clone, Hash, PartialEq, Eq)]
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
enum Status {
Two,
#[allow(dead_code)]
Expand All @@ -34,34 +33,19 @@ pub fn text(c: &mut Criterion) {
Five,
}

impl prometheus_client::encoding::text::Encode for Status {
fn encode(&self, writer: &mut dyn Write) -> Result<(), std::io::Error> {
impl prometheus_client::encoding::EncodeLabelValue for Status {
fn encode(&self, writer: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
let status = match self {
Status::Two => b"200",
Status::Four => b"400",
Status::Five => b"500",
Status::Two => "200",
Status::Four => "400",
Status::Five => "500",
};
writer.write_all(status)?;
writer.write_str(status)?;
Ok(())
}
}

#[cfg(feature = "protobuf")]
impl prometheus_client::encoding::proto::EncodeLabels for Status {
fn encode(&self, labels: &mut Vec<prometheus_client::encoding::proto::Label>) {
let value = match self {
Status::Two => "200".to_string(),
Status::Four => "400".to_string(),
Status::Five => "500".to_string(),
};
labels.push(prometheus_client::encoding::proto::Label {
name: "status".to_string(),
value,
});
}
}

let mut registry = Registry::<Box<dyn EncodeMetric>>::default();
let mut registry = Registry::default();

for i in 0..100 {
let counter_family = Family::<Labels, Counter>::default();
Expand All @@ -72,12 +56,12 @@ pub fn text(c: &mut Criterion) {
registry.register(
format!("my_counter_{}", i),
"My counter",
Box::new(counter_family.clone()),
counter_family.clone(),
);
registry.register(
format!("my_histogram_{}", i),
"My histogram",
Box::new(histogram_family.clone()),
histogram_family.clone(),
);

for j in 0u32..100 {
Expand All @@ -98,10 +82,10 @@ pub fn text(c: &mut Criterion) {
}
}

let mut buffer = vec![];
let mut buffer = String::new();

b.iter(|| {
encode(&mut buffer, &registry).unwrap();
encoding::text::encode(&mut buffer, &registry).unwrap();
black_box(&mut buffer);
})
});
Expand Down
3 changes: 0 additions & 3 deletions derive-encode/Cargo.toml
Expand Up @@ -9,9 +9,6 @@ repository = "https://github.com/prometheus/client_rust"
homepage = "https://github.com/prometheus/client_rust"
documentation = "https://docs.rs/prometheus-client-derive-text-encode"

[features]
protobuf = []

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand Down