diff --git a/metrics-exporter-prometheus/Cargo.toml b/metrics-exporter-prometheus/Cargo.toml index 74f25a8..a18079c 100644 --- a/metrics-exporter-prometheus/Cargo.toml +++ b/metrics-exporter-prometheus/Cargo.toml @@ -15,15 +15,21 @@ readme = "README.md" categories = ["development-tools::debugging"] keywords = ["metrics", "telemetry", "prometheus"] +[features] +default = ["tokio-exporter"] +tokio-exporter = ["hyper", "tokio"] + [dependencies] metrics = { version = "0.13.0-alpha.1", path = "../metrics" } -metrics-util = { version = "0.4.0-alpha.1", path = "../metrics-util"} +metrics-util = { version = "0.4.0-alpha.1", path = "../metrics-util" } hdrhistogram = "7.1" -hyper = { version = "0.13", default-features = false, features = ["tcp"] } -tokio = { version = "0.2", features = ["rt-core", "tcp", "time", "macros"] } parking_lot = "0.11" thiserror = "1.0" +# Optional +hyper = { version = "0.13", default-features = false, features = ["tcp"], optional = true } +tokio = { version = "0.2", features = ["rt-core", "tcp", "time", "macros"], optional = true } + [dev-dependencies] quanta = "0.6" tracing = "0.1" diff --git a/metrics-exporter-prometheus/src/lib.rs b/metrics-exporter-prometheus/src/lib.rs index 4657d16..033d864 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -3,6 +3,7 @@ #![cfg_attr(docsrs, feature(doc_cfg), deny(broken_intra_doc_links))] use std::future::Future; +#[cfg(feature = "tokio-exporter")] use hyper::{ service::{make_service_fn, service_fn}, {Body, Error as HyperError, Response, Server}, @@ -16,9 +17,11 @@ use std::io; use std::iter::FromIterator; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; +#[cfg(feature = "tokio-exporter")] use std::thread; use std::{collections::HashMap, time::SystemTime}; use thiserror::Error as ThisError; +#[cfg(feature = "tokio-exporter")] use tokio::{pin, runtime, select}; type PrometheusRegistry = Registry; @@ -32,6 +35,7 @@ pub enum Error { Io(#[from] io::Error), /// Binding/listening to the given address did not succeed. + #[cfg(feature = "tokio-exporter")] #[error("failed to bind to given listen address: {0}")] Hyper(#[from] HyperError), @@ -331,6 +335,13 @@ pub struct PrometheusRecorder { } impl PrometheusRecorder { + /// Gets a [`PrometheusHandle`] to this recorder. + pub fn handle(&self) -> PrometheusHandle { + PrometheusHandle { + inner: self.inner.clone(), + } + } + fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) { if let Some(description) = description { let mut descriptions = self.inner.descriptions.write(); @@ -341,6 +352,20 @@ impl PrometheusRecorder { } } +/// Handle to [`PrometheusRecorder`]. +/// +/// Useful for exposing a scrape endpoint on an existing HTTP/HTTPS server. +pub struct PrometheusHandle { + inner: Arc, +} + +impl PrometheusHandle { + /// Returns the metrics in Prometheus accepted String format. + pub fn render(&self) -> String { + self.inner.render() + } +} + /// Builder for creating and installing a Prometheus recorder/exporter. pub struct PrometheusBuilder { listen_address: SocketAddr, @@ -416,8 +441,9 @@ impl PrometheusBuilder { /// /// An error will be returned if there's an issue with creating the HTTP server or with /// installing the recorder as the global recorder. + #[cfg(feature = "tokio-exporter")] pub fn install(self) -> Result<(), Error> { - let (recorder, exporter) = self.build()?; + let (recorder, exporter) = self.build_with_exporter()?; metrics::set_boxed_recorder(Box::new(recorder))?; let mut runtime = runtime::Builder::new() @@ -441,13 +467,31 @@ impl PrometheusBuilder { Ok(()) } + /// Builds the recorder and returns it. + /// This function is only enabled when default features are not set. + pub fn build(self) -> Result { + let inner = Arc::new(Inner { + registry: Registry::new(), + distributions: RwLock::new(HashMap::new()), + quantiles: self.quantiles.clone(), + buckets: self.buckets.clone(), + buckets_by_name: self.buckets_by_name, + descriptions: RwLock::new(HashMap::new()), + }); + + let recorder = PrometheusRecorder { inner }; + + Ok(recorder) + } + /// Builds the recorder and exporter and returns them both. /// /// In most cases, users should prefer to use [`PrometheusBuilder::install`] to create and /// install the recorder and exporter automatically for them. If a caller is combining /// recorders, or needs to schedule the exporter to run in a particular way, this method /// provides the flexibility to do so. - pub fn build( + #[cfg(feature = "tokio-exporter")] + pub fn build_with_exporter( self, ) -> Result< (