Skip to content

Commit d9398af

Browse files
committed
Merge branch 'master' of https://github.com/prometheus/client_rust into fix_issue_172
2 parents 53d02ba + 24a8ada commit d9398af

File tree

13 files changed

+488
-72
lines changed

13 files changed

+488
-72
lines changed

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,46 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.23.0] - unreleased
8+
9+
- Update `prost` dependencies to `v0.12`.
10+
See [PR 198].
11+
12+
[PR 198]: https://github.com/prometheus/client_rust/pull/198
13+
14+
## [0.22.3]
15+
16+
### Added
17+
18+
- Added `encode_registry` and `encode_eof` functions to `text` module.
19+
See [PR 205].
20+
21+
[PR 205]: https://github.com/prometheus/client_rust/pull/205
22+
23+
- Support all platforms with 32 bit atomics lacking 64 bit atomics.
24+
See [PR 203].
25+
26+
[PR 203]: https://github.com/prometheus/client_rust/pull/203
27+
28+
## [0.22.2]
29+
30+
### Added
31+
32+
- Added `Gauge<u32, AtomicU32>` implementation.
33+
See [PR 191].
34+
35+
[PR 191]: https://github.com/prometheus/client_rust/pull/191
36+
37+
## [0.22.1]
38+
39+
### Added
40+
41+
- Added `EncodeLabelValue` and `EncodeLabelKey` implementations for `Arc`,
42+
`Rc`, and `Box`.
43+
See [PR 188].
44+
45+
[PR 188]: https://github.com/prometheus/client_rust/pull/188
46+
747
## [0.22.0]
848

949
### Changed

Cargo.toml

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "prometheus-client"
3-
version = "0.22.0"
3+
version = "0.23.0"
44
authors = ["Max Inden <[email protected]>"]
55
edition = "2021"
66
description = "Open Metrics client library allowing users to natively instrument applications."
@@ -22,23 +22,29 @@ dtoa = "1.0"
2222
itoa = "1.0"
2323
parking_lot = "0.12"
2424
prometheus-client-derive-encode = { version = "0.4.1", path = "derive-encode" }
25-
prost = { version = "0.11.0", optional = true }
26-
prost-types = { version = "0.11.0", optional = true }
25+
prost = { version = "0.12.0", optional = true }
26+
prost-types = { version = "0.12.0", optional = true }
2727

2828
[dev-dependencies]
2929
async-std = { version = "1", features = ["attributes"] }
3030
criterion = "0.5"
3131
http-types = "2"
32-
pyo3 = "0.20"
32+
pyo3 = "0.21"
3333
quickcheck = "1"
3434
rand = "0.8.4"
3535
tide = "0.16"
3636
actix-web = "4"
3737
tokio = { version = "1", features = ["rt-multi-thread", "net", "macros", "signal"] }
38-
hyper = { version = "0.14.16", features = ["server", "http1", "tcp"] }
38+
hyper = { version = "1.3.1", features = ["server", "http1"] }
39+
hyper-util = { version = "0.1.3", features = ["tokio"] }
40+
http-body-util = "0.1.1"
3941

4042
[build-dependencies]
41-
prost-build = { version = "0.11.0", optional = true }
43+
prost-build = { version = "0.12.0", optional = true }
44+
45+
[[bench]]
46+
name = "baseline"
47+
harness = false
4248

4349
[[bench]]
4450
name = "family"
@@ -54,4 +60,9 @@ required-features = []
5460
name = "proto"
5561
path = "benches/encoding/proto.rs"
5662
harness = false
57-
required-features = ["protobuf"]
63+
required-features = ["protobuf"]
64+
65+
# Passing arguments to the docsrs builder in order to properly document cfg's.
66+
# More information: https://docs.rs/about/builds#cross-compiling
67+
[package.metadata.docs.rs]
68+
all-features = true

benches/baseline.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
use prometheus_client::metrics::counter::Counter;
3+
use prometheus_client::metrics::family::Family;
4+
5+
pub fn baseline(c: &mut Criterion) {
6+
c.bench_function("counter", |b| {
7+
let counter: Counter = Counter::default();
8+
9+
b.iter(|| {
10+
counter.inc();
11+
})
12+
});
13+
14+
c.bench_function("counter via family lookup", |b| {
15+
let family = Family::<(), Counter>::default();
16+
17+
b.iter(|| {
18+
family.get_or_create(&()).inc();
19+
})
20+
});
21+
}
22+
23+
criterion_group!(benches, baseline);
24+
criterion_main!(benches);

benches/family.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@ use prometheus_client::metrics::counter::Counter;
33
use prometheus_client::metrics::family::Family;
44

55
pub fn family(c: &mut Criterion) {
6+
c.bench_function(
7+
"counter family with [(&'static str, &'static str)] label set",
8+
|b| {
9+
let family = Family::<[(&'static str, &'static str); 2], Counter>::default();
10+
11+
b.iter(|| {
12+
family
13+
.get_or_create(&[("method", "GET"), ("status", "200")])
14+
.inc();
15+
})
16+
},
17+
);
18+
19+
c.bench_function(
20+
"counter family with Vec<(&'static str, &'static str)> label set",
21+
|b| {
22+
let family = Family::<Vec<(&'static str, &'static str)>, Counter>::default();
23+
24+
b.iter(|| {
25+
family
26+
.get_or_create(&vec![("method", "GET"), ("status", "200")])
27+
.inc();
28+
})
29+
},
30+
);
31+
632
c.bench_function("counter family with Vec<(String, String)> label set", |b| {
733
let family = Family::<Vec<(String, String)>, Counter>::default();
834

examples/actix-web.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::sync::Mutex;
22

3+
use actix_web::middleware::Compress;
34
use actix_web::{web, App, HttpResponse, HttpServer, Responder, Result};
45
use prometheus_client::encoding::text::encode;
56
use prometheus_client::encoding::{EncodeLabelSet, EncodeLabelValue};
@@ -61,6 +62,7 @@ async fn main() -> std::io::Result<()> {
6162

6263
HttpServer::new(move || {
6364
App::new()
65+
.wrap(Compress::default())
6466
.app_data(metrics.clone())
6567
.app_data(state.clone())
6668
.service(web::resource("/metrics").route(web::get().to(metrics_handler)))

examples/hyper.rs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
use http_body_util::{combinators, BodyExt, Full};
12
use hyper::{
2-
service::{make_service_fn, service_fn},
3-
Body, Request, Response, Server,
3+
body::{Bytes, Incoming},
4+
server::conn::http1,
5+
service::service_fn,
6+
Request, Response,
47
};
8+
use hyper_util::rt::TokioIo;
59
use prometheus_client::{encoding::text::encode, metrics::counter::Counter, registry::Registry};
610
use std::{
711
future::Future,
@@ -10,7 +14,11 @@ use std::{
1014
pin::Pin,
1115
sync::Arc,
1216
};
13-
use tokio::signal::unix::{signal, SignalKind};
17+
use tokio::{
18+
net::TcpListener,
19+
pin,
20+
signal::unix::{signal, SignalKind},
21+
};
1422

1523
#[tokio::main]
1624
async fn main() {
@@ -31,39 +39,48 @@ async fn main() {
3139

3240
/// Start a HTTP server to report metrics.
3341
pub async fn start_metrics_server(metrics_addr: SocketAddr, registry: Registry) {
34-
let mut shutdown_stream = signal(SignalKind::terminate()).unwrap();
35-
3642
eprintln!("Starting metrics server on {metrics_addr}");
3743

3844
let registry = Arc::new(registry);
39-
Server::bind(&metrics_addr)
40-
.serve(make_service_fn(move |_conn| {
41-
let registry = registry.clone();
42-
async move {
43-
let handler = make_handler(registry);
44-
Ok::<_, io::Error>(service_fn(handler))
45+
46+
let tcp_listener = TcpListener::bind(metrics_addr).await.unwrap();
47+
let server = http1::Builder::new();
48+
while let Ok((stream, _)) = tcp_listener.accept().await {
49+
let mut shutdown_stream = signal(SignalKind::terminate()).unwrap();
50+
let io = TokioIo::new(stream);
51+
let server_clone = server.clone();
52+
let registry_clone = registry.clone();
53+
tokio::task::spawn(async move {
54+
let conn = server_clone.serve_connection(io, service_fn(make_handler(registry_clone)));
55+
pin!(conn);
56+
tokio::select! {
57+
_ = conn.as_mut() => {}
58+
_ = shutdown_stream.recv() => {
59+
conn.as_mut().graceful_shutdown();
60+
}
4561
}
46-
}))
47-
.with_graceful_shutdown(async move {
48-
shutdown_stream.recv().await;
49-
})
50-
.await
51-
.unwrap();
62+
});
63+
}
5264
}
5365

66+
/// Boxed HTTP body for responses
67+
type BoxBody = combinators::BoxBody<Bytes, hyper::Error>;
68+
5469
/// This function returns a HTTP handler (i.e. another function)
5570
pub fn make_handler(
5671
registry: Arc<Registry>,
57-
) -> impl Fn(Request<Body>) -> Pin<Box<dyn Future<Output = io::Result<Response<Body>>> + Send>> {
72+
) -> impl Fn(Request<Incoming>) -> Pin<Box<dyn Future<Output = io::Result<Response<BoxBody>>> + Send>>
73+
{
5874
// This closure accepts a request and responds with the OpenMetrics encoding of our metrics.
59-
move |_req: Request<Body>| {
75+
move |_req: Request<Incoming>| {
6076
let reg = registry.clone();
77+
6178
Box::pin(async move {
6279
let mut buf = String::new();
6380
encode(&mut buf, &reg.clone())
6481
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
6582
.map(|_| {
66-
let body = Body::from(buf);
83+
let body = full(Bytes::from(buf));
6784
Response::builder()
6885
.header(
6986
hyper::header::CONTENT_TYPE,
@@ -75,3 +92,8 @@ pub fn make_handler(
7592
})
7693
}
7794
}
95+
96+
/// helper function to build a full boxed body
97+
pub fn full(body: Bytes) -> BoxBody {
98+
Full::new(body).map_err(|never| match never {}).boxed()
99+
}

src/encoding.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ use std::borrow::Cow;
99
use std::collections::HashMap;
1010
use std::fmt::Write;
1111
use std::ops::Deref;
12+
use std::rc::Rc;
13+
use std::sync::Arc;
1214

1315
#[cfg(feature = "protobuf")]
16+
#[cfg_attr(docsrs, doc(cfg(feature = "protobuf")))]
1417
pub mod protobuf;
1518
pub mod text;
1619

@@ -389,6 +392,33 @@ impl<'a> EncodeLabelKey for Cow<'a, str> {
389392
}
390393
}
391394

395+
impl<T> EncodeLabelKey for Box<T>
396+
where
397+
for<'a> &'a T: EncodeLabelKey,
398+
{
399+
fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
400+
EncodeLabelKey::encode(&self.as_ref(), encoder)
401+
}
402+
}
403+
404+
impl<T> EncodeLabelKey for Arc<T>
405+
where
406+
for<'a> &'a T: EncodeLabelKey,
407+
{
408+
fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
409+
EncodeLabelKey::encode(&self.as_ref(), encoder)
410+
}
411+
}
412+
413+
impl<T> EncodeLabelKey for Rc<T>
414+
where
415+
for<'a> &'a T: EncodeLabelKey,
416+
{
417+
fn encode(&self, encoder: &mut LabelKeyEncoder) -> Result<(), std::fmt::Error> {
418+
EncodeLabelKey::encode(&self.as_ref(), encoder)
419+
}
420+
}
421+
392422
/// An encodable label value.
393423
pub trait EncodeLabelValue {
394424
/// Encode oneself into the given encoder.
@@ -450,6 +480,33 @@ impl<'a> EncodeLabelValue for Cow<'a, str> {
450480
}
451481
}
452482

483+
impl<T> EncodeLabelValue for Box<T>
484+
where
485+
for<'a> &'a T: EncodeLabelValue,
486+
{
487+
fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
488+
EncodeLabelValue::encode(&self.as_ref(), encoder)
489+
}
490+
}
491+
492+
impl<T> EncodeLabelValue for Arc<T>
493+
where
494+
for<'a> &'a T: EncodeLabelValue,
495+
{
496+
fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
497+
EncodeLabelValue::encode(&self.as_ref(), encoder)
498+
}
499+
}
500+
501+
impl<T> EncodeLabelValue for Rc<T>
502+
where
503+
for<'a> &'a T: EncodeLabelValue,
504+
{
505+
fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
506+
EncodeLabelValue::encode(&self.as_ref(), encoder)
507+
}
508+
}
509+
453510
impl EncodeLabelValue for f64 {
454511
fn encode(&self, encoder: &mut LabelValueEncoder) -> Result<(), std::fmt::Error> {
455512
encoder.write_str(dtoa::Buffer::new().format(*self))
@@ -488,6 +545,12 @@ pub trait EncodeGaugeValue {
488545
fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error>;
489546
}
490547

548+
impl EncodeGaugeValue for u32 {
549+
fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
550+
encoder.encode_u32(*self)
551+
}
552+
}
553+
491554
impl EncodeGaugeValue for i64 {
492555
fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> {
493556
encoder.encode_i64(*self)
@@ -524,13 +587,17 @@ enum GaugeValueEncoderInner<'a> {
524587
}
525588

526589
impl<'a> GaugeValueEncoder<'a> {
527-
fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> {
528-
for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_f64(v))
590+
fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> {
591+
for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_u32(v))
529592
}
530593

531594
fn encode_i64(&mut self, v: i64) -> Result<(), std::fmt::Error> {
532595
for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_i64(v))
533596
}
597+
598+
fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> {
599+
for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_f64(v))
600+
}
534601
}
535602

536603
impl<'a> From<text::GaugeValueEncoder<'a>> for GaugeValueEncoder<'a> {

src/encoding/protobuf.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ pub(crate) struct GaugeValueEncoder<'a> {
323323
}
324324

325325
impl<'a> GaugeValueEncoder<'a> {
326+
pub fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> {
327+
self.encode_i64(v as i64)
328+
}
329+
326330
pub fn encode_i64(&mut self, v: i64) -> Result<(), std::fmt::Error> {
327331
*self.value = openmetrics_data_model::gauge_value::Value::IntValue(v);
328332
Ok(())

0 commit comments

Comments
 (0)