Skip to content

Commit 5021289

Browse files
committed
example: Use hyper to serve metrics
Signed-off-by: Adam Chalmers <[email protected]>
1 parent 5b3aa2c commit 5021289

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,17 @@ quickcheck = "1"
3434
rand = "0.8.4"
3535
tide = "0.16"
3636
actix-web = "4"
37+
tokio = { version = "1", features = ["rt-multi-thread", "net", "macros", "signal"] }
38+
hyper = { version = "0.14.16", features = ["server", "http1", "tcp"] }
39+
lazy_static = "1.4"
3740

3841
[build-dependencies]
3942
prost-build = { version = "0.9.0", optional = true }
4043

44+
[[example]]
45+
name = "hyper"
46+
crate-type = ["bin"]
47+
4148
[[bench]]
4249
name = "family"
4350
harness = false

examples/hyper.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use hyper::{
2+
service::{make_service_fn, service_fn},
3+
Body, Request, Response, Server,
4+
};
5+
use prometheus_client::{encoding::text::encode, metrics::counter::Counter, registry::Registry};
6+
use std::{
7+
future::Future,
8+
io,
9+
net::{IpAddr, Ipv4Addr, SocketAddr},
10+
pin::Pin,
11+
sync::Arc,
12+
time::Duration,
13+
};
14+
use tokio::signal::unix::{signal, SignalKind};
15+
16+
lazy_static::lazy_static! {
17+
pub static ref EXAMPLE_COUNTER: Counter = Counter::default();
18+
}
19+
20+
#[tokio::main]
21+
async fn main() {
22+
let registry = register_metrics();
23+
24+
// Spawn a server to serve the OpenMetrics endpoint.
25+
let metrics_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8001);
26+
tokio::task::spawn(start_server(metrics_addr, registry));
27+
28+
loop {
29+
EXAMPLE_COUNTER.inc();
30+
tokio::time::sleep(Duration::from_secs(1)).await;
31+
}
32+
}
33+
34+
pub fn register_metrics() -> Registry {
35+
let mut registry = <Registry>::with_prefix("tokio_hyper_example");
36+
37+
registry.register(
38+
"example_counter",
39+
"An example counter that will get incremented automatically",
40+
Box::new(EXAMPLE_COUNTER.clone()),
41+
);
42+
43+
registry
44+
}
45+
46+
/// Start a HTTP server to report metrics.
47+
pub async fn start_server(metrics_addr: SocketAddr, registry: Registry) {
48+
let mut shutdown_stream = signal(SignalKind::terminate()).unwrap();
49+
50+
eprintln!("Starting metrics server on {metrics_addr}");
51+
52+
let registry = Arc::new(registry);
53+
Server::bind(&metrics_addr)
54+
.serve(make_service_fn(move |_conn| {
55+
let registry = registry.clone();
56+
async move {
57+
let handler = make_handler(registry);
58+
Ok::<_, io::Error>(service_fn(handler))
59+
}
60+
}))
61+
.with_graceful_shutdown(async move {
62+
shutdown_stream.recv().await;
63+
})
64+
.await
65+
.unwrap();
66+
}
67+
68+
/// This function returns a HTTP handler (i.e. another function)
69+
pub fn make_handler(
70+
registry: Arc<Registry>,
71+
) -> impl Fn(Request<Body>) -> Pin<Box<dyn Future<Output = io::Result<Response<Body>>> + Send>> {
72+
// This closure accepts a request and responds with the OpenMetrics encoding of our metrics.
73+
move |_req: Request<Body>| {
74+
let reg = registry.clone();
75+
Box::pin(async move {
76+
let mut buf = Vec::new();
77+
encode(&mut buf, &reg.clone()).map(|_| {
78+
let body = std::str::from_utf8(buf.as_slice()).unwrap().to_string();
79+
Response::builder()
80+
.header(
81+
hyper::header::CONTENT_TYPE,
82+
"application/openmetrics-text; version=1.0.0; charset=utf-8",
83+
)
84+
.body(Body::from(body))
85+
.unwrap()
86+
})
87+
})
88+
}
89+
}

0 commit comments

Comments
 (0)