metrics_exporter_http_async_std/
lib.rs

1//! Exports metrics over HTTP.
2//!
3//! This exporter can utilize observers that are able to be converted to a textual representation
4//! via [`Drain<String>`].  It will respond to any requests, regardless of the method or path.
5//!
6//! Awaiting on `async_run` will drive an HTTP server listening on the configured address.
7#![deny(missing_docs)]
8
9use async_std::net::TcpListener;
10use async_std::prelude::*;
11use metrics_core::{Builder, Drain, Observe, Observer};
12use std::net::SocketAddr;
13
14/// Exports metrics over HTTP.
15pub struct HttpExporter<C, B> {
16    controller: C,
17    builder: B,
18    address: SocketAddr,
19}
20
21impl<C, B> HttpExporter<C, B>
22where
23    C: Observe + Send + Sync + 'static,
24    B: Builder + Send + Sync + 'static,
25    B::Output: Drain<String> + Observer,
26{
27    /// Creates a new [`HttpExporter`] that listens on the given `address`.
28    ///
29    /// Observers expose their output by being converted into strings.
30    pub fn new(controller: C, builder: B, address: SocketAddr) -> Self {
31        HttpExporter {
32            controller,
33            builder,
34            address,
35        }
36    }
37
38    /// Starts an HTTP server on the `address` the exporter was originally configured with,
39    /// responding to any request with the output of the configured observer.
40    pub async fn async_run(self) -> std::io::Result<()> {
41        let builder = self.builder;
42        let controller = self.controller;
43
44        let listener = TcpListener::bind(self.address).await?;
45        let mut incoming = listener.incoming();
46
47        while let Some(stream) = incoming.next().await {
48            let mut stream = stream?;
49
50            // seems like we have to read before writing if not we get an "Connection reset by peer"
51            // cUrl and firefox are ok with 512 bytes but Chrome needs some more just in case we read 1024 bytes.
52            let mut buffer = [0; 1024];
53            stream.read(&mut buffer).await?;
54
55            let mut observer = builder.build();
56            controller.observe(&mut observer);
57            let output = observer.drain();
58
59            let response = format!("HTTP/1.1 200\r\n\r\n{}", output);
60            stream.write_all(response.as_bytes()).await?;
61        }
62
63        Ok(())
64    }
65}