Skip to content

Commit 00e9508

Browse files
committed
derive-encode: Fix compilation
1 parent d4bd695 commit 00e9508

File tree

7 files changed

+90
-69
lines changed

7 files changed

+90
-69
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ documentation = "https://docs.rs/prometheus-client"
1313
[features]
1414
# TODO: Revert
1515
default = ["protobuf"]
16-
protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build", "dep:void", "prometheus-client-derive-encode/protobuf"]
16+
protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build", "dep:void"]
1717

1818
[workspace]
1919
members = ["derive-encode"]

derive-encode/Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ repository = "https://github.com/prometheus/client_rust"
99
homepage = "https://github.com/prometheus/client_rust"
1010
documentation = "https://docs.rs/prometheus-client-derive-text-encode"
1111

12-
[features]
13-
protobuf = []
14-
1512
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1613

1714
[dependencies]
@@ -20,7 +17,7 @@ quote = "1"
2017
syn = "1"
2118

2219
[dev-dependencies]
23-
prometheus-client = { path = "../", features = ["protobuf"] }
20+
prometheus-client = { path = "../", all-features = true }
2421

2522
[lib]
2623
proc-macro = true

derive-encode/src/lib.rs

+49-27
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,32 @@ use proc_macro2::TokenStream as TokenStream2;
55
use quote::quote;
66
use syn::DeriveInput;
77

8-
#[proc_macro_derive(Encode)]
9-
pub fn derive_encode(input: TokenStream) -> TokenStream {
8+
#[proc_macro_derive(EncodeLabelSet)]
9+
pub fn derive_encode_label_set(input: TokenStream) -> TokenStream {
1010
let ast: DeriveInput = syn::parse(input).unwrap();
1111
let name = &ast.ident;
1212

13-
let body = match ast.clone().data {
13+
let body: TokenStream2 = match ast.clone().data {
1414
syn::Data::Struct(s) => match s.fields {
1515
syn::Fields::Named(syn::FieldsNamed { named, .. }) => named
1616
.into_iter()
17-
.enumerate()
18-
.map(|(i, f)| {
17+
.map(|f| {
1918
let ident = f.ident.unwrap();
2019
let ident_string = KEYWORD_IDENTIFIERS
2120
.iter()
2221
.find(|pair| ident == pair.1)
2322
.map(|pair| pair.0.to_string())
2423
.unwrap_or_else(|| ident.to_string());
2524

26-
let maybe_comma = if i == 0 {
27-
TokenStream2::default()
28-
} else {
29-
quote! { writer.write_all(b",")?; }
30-
};
3125
quote! {
32-
#maybe_comma
33-
writer.write_all(concat!(#ident_string, "=\"").as_bytes())?;
34-
prometheus_client::encoding::text::Encode::encode(&self.#ident, writer)?;
35-
writer.write_all(b"\"")?;
26+
let mut label_encoder = encoder.encode_label();
27+
let mut label_key_encoder = label_encoder.encode_label_key();
28+
EncodeLabelKey::encode(&#ident_string, &mut label_key_encoder)?;
29+
30+
let mut label_value_encoder = label_key_encoder.encode_label_value()?;
31+
EncodeLabelValue::encode(&self.#ident, &mut label_value_encoder)?;
32+
33+
label_value_encoder.finish()?;
3634
}
3735
})
3836
.collect(),
@@ -41,13 +39,45 @@ pub fn derive_encode(input: TokenStream) -> TokenStream {
4139
}
4240
syn::Fields::Unit => panic!("Can not derive Encode for struct with unit field."),
4341
},
42+
syn::Data::Enum(syn::DataEnum { .. }) => {
43+
panic!("Can not derive Encode for enum.")
44+
}
45+
syn::Data::Union(_) => panic!("Can not derive Encode for union."),
46+
};
47+
48+
let gen = quote! {
49+
impl prometheus_client::encoding::EncodeLabelSet for #name {
50+
fn encode(&self, mut encoder: prometheus_client::encoding::LabelSetEncoder) -> Result<(), std::fmt::Error> {
51+
use prometheus_client::encoding::EncodeLabel;
52+
use prometheus_client::encoding::EncodeLabelKey;
53+
use prometheus_client::encoding::EncodeLabelValue;
54+
55+
#body
56+
57+
Ok(())
58+
}
59+
}
60+
};
61+
62+
gen.into()
63+
}
64+
65+
#[proc_macro_derive(EncodeLabelValue)]
66+
pub fn derive_encode_label_value(input: TokenStream) -> TokenStream {
67+
let ast: DeriveInput = syn::parse(input).unwrap();
68+
let name = &ast.ident;
69+
70+
let body = match ast.clone().data {
71+
syn::Data::Struct(_) => {
72+
panic!("Can not derive EncodeLabel for struct.")
73+
}
4474
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
4575
let match_arms: TokenStream2 = variants
4676
.into_iter()
4777
.map(|v| {
4878
let ident = v.ident;
4979
quote! {
50-
#name::#ident => writer.write_all(stringify!(#ident).as_bytes())?,
80+
#name::#ident => encoder.write_str(stringify!(#ident))?,
5181
}
5282
})
5383
.collect();
@@ -62,25 +92,17 @@ pub fn derive_encode(input: TokenStream) -> TokenStream {
6292
};
6393

6494
let gen = quote! {
65-
impl prometheus_client::encoding::text::Encode for #name {
66-
fn encode(&self, writer: &mut dyn std::io::Write) -> std::result::Result<(), std::io::Error> {
95+
impl prometheus_client::encoding::EncodeLabelValue for #name {
96+
fn encode(&self, encoder: &mut prometheus_client::encoding::LabelValueEncoder) -> Result<(), std::fmt::Error> {
97+
use std::fmt::Write;
98+
6799
#body
68100

69101
Ok(())
70102
}
71103
}
72104
};
73105

74-
#[cfg(feature = "protobuf")]
75-
let gen = {
76-
let protobuf = derive_protobuf_encode(ast);
77-
quote! {
78-
#gen
79-
80-
#protobuf
81-
}
82-
};
83-
84106
gen.into()
85107
}
86108

derive-encode/tests/lib.rs

+29-21
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
use prometheus_client::encoding::text::encode;
2-
use prometheus_client::encoding::Encode;
2+
use prometheus_client::encoding::{EncodeLabelSet, EncodeLabelValue};
33
use prometheus_client::metrics::counter::Counter;
44
use prometheus_client::metrics::family::Family;
55
use prometheus_client::registry::Registry;
66

7-
#[derive(Clone, Hash, PartialEq, Eq, Encode)]
7+
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
88
struct Labels {
99
method: Method,
1010
path: String,
1111
}
1212

13-
#[derive(Clone, Hash, PartialEq, Eq, Encode)]
13+
#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
1414
enum Method {
1515
Get,
1616
#[allow(dead_code)]
@@ -33,17 +33,17 @@ fn basic_flow() {
3333
.inc();
3434

3535
// Encode all metrics in the registry in the text format.
36-
let mut buffer = vec![];
36+
let mut buffer = String::new();
3737
encode(&mut buffer, &registry).unwrap();
3838

3939
let expected = "# HELP my_counter This is my counter.\n".to_owned()
4040
+ "# TYPE my_counter counter\n"
4141
+ "my_counter_total{method=\"Get\",path=\"/metrics\"} 1\n"
4242
+ "# EOF\n";
43-
assert_eq!(expected, String::from_utf8(buffer).unwrap());
43+
assert_eq!(expected, buffer);
4444
}
4545

46-
#[cfg(feature = "protobuf")]
46+
// TODO: Remove protobuf module wrapper
4747
mod protobuf {
4848
use crate::{Labels, Method};
4949
use prometheus_client::encoding::proto::encode;
@@ -66,7 +66,7 @@ mod protobuf {
6666
.inc();
6767

6868
// Encode all metrics in the registry in the OpenMetrics protobuf format.
69-
let mut metric_set = encode(&registry);
69+
let mut metric_set = encode(&registry).unwrap();
7070
let mut family: prometheus_client::encoding::proto::MetricFamily =
7171
metric_set.metric_families.pop().unwrap();
7272
let metric: prometheus_client::encoding::proto::Metric = family.metrics.pop().unwrap();
@@ -83,14 +83,19 @@ mod protobuf {
8383
#[test]
8484
fn enums() {
8585
let mut registry = Registry::default();
86-
let family = Family::<Method, Counter>::default();
86+
let family = Family::<Labels, Counter>::default();
8787
registry.register("my_counter", "This is my counter", family.clone());
8888

8989
// Record a single HTTP GET request.
90-
family.get_or_create(&Method::Get).inc();
90+
family
91+
.get_or_create(&Labels {
92+
method: Method::Get,
93+
path: "/metrics".to_string(),
94+
})
95+
.inc();
9196

9297
// Encode all metrics in the registry in the OpenMetrics protobuf format.
93-
let mut metric_set = encode(&registry);
98+
let mut metric_set = encode(&registry).unwrap();
9499
let mut family: prometheus_client::encoding::proto::MetricFamily =
95100
metric_set.metric_families.pop().unwrap();
96101
let metric: prometheus_client::encoding::proto::Metric = family.metrics.pop().unwrap();
@@ -103,7 +108,7 @@ mod protobuf {
103108

104109
#[test]
105110
fn remap_keyword_identifiers() {
106-
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
111+
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
107112
struct Labels {
108113
// `r#type` is problematic as `r#` is not a valid OpenMetrics label name
109114
// but one needs to use keyword identifier syntax (aka. raw identifiers)
@@ -114,17 +119,20 @@ fn remap_keyword_identifiers() {
114119
r#type: u64,
115120
}
116121

117-
let labels = Labels { r#type: 42 };
122+
let mut registry = Registry::default();
123+
let family = Family::<Labels, Counter>::default();
124+
registry.register("my_counter", "This is my counter", family.clone());
118125

119-
let mut buffer = vec![];
126+
// Record a single HTTP GET request.
127+
family.get_or_create(&Labels { r#type: 42 }).inc();
120128

121-
{
122-
use prometheus_client::encoding::text::Encode;
123-
labels.encode(&mut buffer).unwrap();
124-
}
129+
// Encode all metrics in the registry in the text format.
130+
let mut buffer = String::new();
131+
encode(&mut buffer, &registry).unwrap();
125132

126-
assert_eq!(
127-
"type=\"42\"".to_string(),
128-
String::from_utf8(buffer).unwrap()
129-
);
133+
let expected = "# HELP my_counter This is my counter.\n".to_owned()
134+
+ "# TYPE my_counter counter\n"
135+
+ "my_counter_total{type=\"42\"} 1\n"
136+
+ "# EOF\n";
137+
assert_eq!(expected, buffer);
130138
}

examples/custom-metric.rs

+7-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use prometheus_client::encoding::{text::encode, EncodeMetric, EncodeValue, MetricEncoder};
1+
use prometheus_client::encoding::{text::encode, EncodeMetric, MetricEncoder};
22
use prometheus_client::metrics::MetricType;
33
use prometheus_client::registry::Registry;
44

@@ -16,22 +16,16 @@ impl EncodeMetric for MyCustomMetric {
1616
// to execute whatever logic is needed to generate and encode your
1717
// custom metric.
1818
//
19-
// While the `Encoder`'s builder pattern should guide you well and makes
20-
// many mistakes impossible at the type level, do keep in mind that
21-
// "with great power comes great responsibility". E.g. every CPU cycle
22-
// spend in this method delays the response send to the Prometheus
23-
// server.
19+
// Do keep in mind that "with great power comes great responsibility".
20+
// E.g. every CPU cycle spend in this method delays the response send to
21+
// the Prometheus server.
2422

25-
let mut bucket_encoder = encoder.no_suffix()?;
26-
let mut value_encoder = bucket_encoder.no_bucket()?;
27-
28-
rand::random::<u32>().encode(&mut value_encoder)?;
29-
30-
Ok(())
23+
// TODO: Ideally the type hints would not be needed.
24+
encoder.encode_counter::<(), u64>(rand::random::<u64>(), None)
3125
}
3226

3327
fn metric_type(&self) -> prometheus_client::metrics::MetricType {
34-
MetricType::Unknown
28+
MetricType::Counter
3529
}
3630
}
3731

src/encoding.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ pub enum LabelValueEncoder<'a> {
220220

221221
impl<'a> LabelValueEncoder<'a> {
222222
#[must_use]
223-
fn finish(self) -> Result<(), std::fmt::Error> {
223+
pub fn finish(self) -> Result<(), std::fmt::Error> {
224224
for_both!(self, e, e.finish())
225225
}
226226
}

src/metrics/gauge.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ use std::sync::Arc;
4242
/// ```
4343
#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))]
4444
#[derive(Debug)]
45-
pub struct Gauge<N = u64, A = AtomicU64> {
45+
pub struct Gauge<N = i64, A = AtomicI64> {
4646
value: Arc<A>,
4747
phantom: PhantomData<N>,
4848
}
4949

5050
/// Open Metrics [`Gauge`] to record current measurements.
5151
#[cfg(any(target_arch = "mips", target_arch = "powerpc"))]
5252
#[derive(Debug)]
53-
pub struct Gauge<N = u32, A = AtomicU32> {
53+
pub struct Gauge<N = i32, A = AtomicI32> {
5454
value: Arc<A>,
5555
phantom: PhantomData<N>,
5656
}

0 commit comments

Comments
 (0)