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

feat(encoding)!: EncodeLabelSet::encode() uses reference #257

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.23.1] - unreleased
## [0.24.0] - unreleased

### Added

- `EncodeLabelSet` is now implemented for tuples `(A: EncodeLabelSet, B: EncodeLabelSet)`.

### Changed

- `EncodeLabelSet::encode()` now accepts a mutable reference to its encoder parameter.

## [0.23.1]

### Changed

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "prometheus-client"
version = "0.23.1"
version = "0.24.0"
authors = ["Max Inden <[email protected]>"]
edition = "2021"
description = "Open Metrics client library allowing users to natively instrument applications."
Expand All @@ -21,7 +21,7 @@ members = ["derive-encode"]
dtoa = "1.0"
itoa = "1.0"
parking_lot = "0.12"
prometheus-client-derive-encode = { version = "0.4.1", path = "derive-encode" }
prometheus-client-derive-encode = { version = "0.5.0", path = "derive-encode" }
prost = { version = "0.12.0", optional = true }
prost-types = { version = "0.12.0", optional = true }

Expand Down
2 changes: 1 addition & 1 deletion derive-encode/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "prometheus-client-derive-encode"
version = "0.4.2"
version = "0.5.0"
authors = ["Max Inden <[email protected]>"]
edition = "2021"
description = "Auxiliary crate to derive Encode trait from prometheus-client."
Expand Down
2 changes: 1 addition & 1 deletion derive-encode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub fn derive_encode_label_set(input: TokenStream) -> TokenStream {

let gen = quote! {
impl prometheus_client::encoding::EncodeLabelSet for #name {
fn encode(&self, mut encoder: prometheus_client::encoding::LabelSetEncoder) -> std::result::Result<(), std::fmt::Error> {
fn encode(&self, encoder: &mut prometheus_client::encoding::LabelSetEncoder) -> std::result::Result<(), std::fmt::Error> {
use prometheus_client::encoding::EncodeLabel;
use prometheus_client::encoding::EncodeLabelKey;
use prometheus_client::encoding::EncodeLabelValue;
Expand Down
28 changes: 22 additions & 6 deletions src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ impl MetricEncoder<'_> {
/// An encodable label set.
pub trait EncodeLabelSet {
/// Encode oneself into the given encoder.
fn encode(&self, encoder: LabelSetEncoder) -> Result<(), std::fmt::Error>;
fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error>;
}

/// Encoder for a label set.
Expand Down Expand Up @@ -238,37 +238,53 @@ impl LabelSetEncoder<'_> {
}

impl<T: EncodeLabel, const N: usize> EncodeLabelSet for [T; N] {
fn encode(&self, encoder: LabelSetEncoder) -> Result<(), std::fmt::Error> {
fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
self.as_ref().encode(encoder)
}
}

impl<T: EncodeLabel> EncodeLabelSet for &[T] {
fn encode(&self, mut encoder: LabelSetEncoder) -> Result<(), std::fmt::Error> {
fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
if self.is_empty() {
return Ok(());
}

for label in self.iter() {
label.encode(encoder.encode_label())?
let encoder = encoder.encode_label();
label.encode(encoder)?
}

Ok(())
}
}

impl<T: EncodeLabel> EncodeLabelSet for Vec<T> {
fn encode(&self, encoder: LabelSetEncoder) -> Result<(), std::fmt::Error> {
fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
self.as_slice().encode(encoder)
}
}

impl<A, B> EncodeLabelSet for (A, B)
where
A: EncodeLabelSet,
B: EncodeLabelSet,
{
fn encode(&self, encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
let (a, b) = self;

a.encode(encoder)?;
b.encode(encoder)?;

Ok(())
}
}

/// Uninhabited type to represent the lack of a label set for a metric
#[derive(Debug)]
pub enum NoLabelSet {}

impl EncodeLabelSet for NoLabelSet {
fn encode(&self, _encoder: LabelSetEncoder) -> Result<(), std::fmt::Error> {
fn encode(&self, _encoder: &mut LabelSetEncoder) -> Result<(), std::fmt::Error> {
Ok(())
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/encoding/protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl DescriptorEncoder<'_> {
};
let mut labels = vec![];
self.labels.encode(
LabelSetEncoder {
&mut LabelSetEncoder {
labels: &mut labels,
}
.into(),
Expand Down Expand Up @@ -210,7 +210,7 @@ impl MetricEncoder<'_> {
) -> Result<(), std::fmt::Error> {
let mut info_labels = vec![];
label_set.encode(
LabelSetEncoder {
&mut LabelSetEncoder {
labels: &mut info_labels,
}
.into(),
Expand All @@ -235,7 +235,7 @@ impl MetricEncoder<'_> {
) -> Result<MetricEncoder, std::fmt::Error> {
let mut labels = self.labels.clone();
label_set.encode(
LabelSetEncoder {
&mut LabelSetEncoder {
labels: &mut labels,
}
.into(),
Expand Down Expand Up @@ -303,7 +303,7 @@ impl<S: EncodeLabelSet, V: EncodeExemplarValue> TryFrom<&Exemplar<S, V>>

let mut labels = vec![];
exemplar.label_set.encode(
LabelSetEncoder {
&mut LabelSetEncoder {
labels: &mut labels,
}
.into(),
Expand Down
69 changes: 62 additions & 7 deletions src/encoding/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,9 @@ pub(crate) struct MetricEncoder<'a> {
impl std::fmt::Debug for MetricEncoder<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut labels = String::new();
let mut encoder = LabelSetEncoder::new(&mut labels).into();
if let Some(l) = self.family_labels {
l.encode(LabelSetEncoder::new(&mut labels).into())?;
l.encode(&mut encoder)?;
}

f.debug_struct("Encoder")
Expand Down Expand Up @@ -451,7 +452,7 @@ impl MetricEncoder<'_> {
self.writer.write_str(" # {")?;
exemplar
.label_set
.encode(LabelSetEncoder::new(self.writer).into())?;
.encode(&mut LabelSetEncoder::new(self.writer).into())?;
self.writer.write_str("} ")?;
exemplar.value.encode(
ExemplarValueEncoder {
Expand Down Expand Up @@ -502,14 +503,14 @@ impl MetricEncoder<'_> {
self.writer.write_str("{")?;

self.const_labels
.encode(LabelSetEncoder::new(self.writer).into())?;
.encode(&mut LabelSetEncoder::new(self.writer).into())?;

if let Some(additional_labels) = additional_labels {
if !self.const_labels.is_empty() {
self.writer.write_str(",")?;
}

additional_labels.encode(LabelSetEncoder::new(self.writer).into())?;
additional_labels.encode(&mut LabelSetEncoder::new(self.writer).into())?;
}

/// Writer impl which prepends a comma on the first call to write output to the wrapped writer
Expand Down Expand Up @@ -539,9 +540,9 @@ impl MetricEncoder<'_> {
writer: self.writer,
should_prepend: true,
};
labels.encode(LabelSetEncoder::new(&mut writer).into())?;
labels.encode(&mut LabelSetEncoder::new(&mut writer).into())?;
} else {
labels.encode(LabelSetEncoder::new(self.writer).into())?;
labels.encode(&mut LabelSetEncoder::new(self.writer).into())?;
};
}

Expand Down Expand Up @@ -936,7 +937,7 @@ mod tests {
struct EmptyLabels {}

impl EncodeLabelSet for EmptyLabels {
fn encode(&self, _encoder: crate::encoding::LabelSetEncoder) -> Result<(), Error> {
fn encode(&self, _encoder: &mut crate::encoding::LabelSetEncoder) -> Result<(), Error> {
Ok(())
}
}
Expand Down Expand Up @@ -1114,6 +1115,60 @@ mod tests {
parse_with_python_client(encoded);
}

#[test]
fn label_sets_can_be_composed() {
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct Color(&'static str);
impl EncodeLabelSet for Color {
fn encode(
&self,
encoder: &mut crate::encoding::LabelSetEncoder,
) -> Result<(), std::fmt::Error> {
use crate::encoding::EncodeLabel;
let Self(color) = *self;
let labels = ("color", color);
let encoder = encoder.encode_label();
labels.encode(encoder)
}
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct Size(&'static str);
impl EncodeLabelSet for Size {
fn encode(
&self,
encoder: &mut crate::encoding::LabelSetEncoder,
) -> Result<(), std::fmt::Error> {
use crate::encoding::EncodeLabel;
let Self(size) = *self;
let labels = ("size", size);
let encoder = encoder.encode_label();
labels.encode(encoder)
}
}

type Labels = (Color, Size);

let mut registry = Registry::default();
let family = Family::<Labels, Counter>::default();
registry.register("items", "Example metric", family.clone());

let labels = (Color("red"), Size("large"));
let counter = family.get_or_create(&labels);
counter.inc();

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

let expected = "# HELP items Example metric.\n\
# TYPE items counter\n\
items_total{color=\"red\",size=\"large\"} 1\n\
# EOF\n";
assert_eq!(expected, encoded);

parse_with_python_client(encoded);
}

#[test]
fn encode_registry_eof() {
let mut orders_registry = Registry::default();
Expand Down
Loading