From 10fc3736c483f2521d8b512b31de39fe7d958eae Mon Sep 17 00:00:00 2001 From: kilpatty Date: Tue, 27 Oct 2020 14:53:57 -0500 Subject: [PATCH 1/9] metrics-exporter-prometheus: split off tokio and hyper functionality to another (default) feature --- metrics-exporter-prometheus/Cargo.toml | 14 +++++++++---- metrics-exporter-prometheus/src/lib.rs | 29 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/metrics-exporter-prometheus/Cargo.toml b/metrics-exporter-prometheus/Cargo.toml index 74f25a8..f1717c1 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 = { version = "0.13.0-alpha.1", path="../metrics" } +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 b374d54..ea4723b 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -2,6 +2,7 @@ #![deny(missing_docs)] use std::future::Future; +#[cfg(feature = "tokio-exporter")] use hyper::{ service::{make_service_fn, service_fn}, {Body, Error as HyperError, Response, Server}, @@ -15,9 +16,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; @@ -31,6 +34,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), @@ -330,6 +334,11 @@ pub struct PrometheusRecorder { } impl PrometheusRecorder { + /// Renders the Prometheus metrics in string format. + pub fn render(&self) -> String { + self.inner.render() + } + fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) { if let Some(description) = description { let mut descriptions = self.inner.descriptions.write(); @@ -414,6 +423,7 @@ 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()?; metrics::set_boxed_recorder(Box::new(recorder))?; @@ -439,12 +449,31 @@ impl PrometheusBuilder { Ok(()) } + /// Builds the recorder and returns it. + /// This function is only enabled when default features are not set. + #[cfg(not(feature = "tokio-exporter"))] + 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. + #[cfg(feature = "tokio-exporter")] pub fn build( self, ) -> Result< From 1b852b32a4c124459d3d2e95c3119c6bcb34e79c Mon Sep 17 00:00:00 2001 From: kilpatty Date: Thu, 29 Oct 2020 16:18:13 -0500 Subject: [PATCH 2/9] metrics-exporter-prometheus: switch methods to gain access to the inner data of the recorder (using a type alias) --- metrics-exporter-prometheus/Cargo.toml | 4 ++-- metrics-exporter-prometheus/src/lib.rs | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/metrics-exporter-prometheus/Cargo.toml b/metrics-exporter-prometheus/Cargo.toml index f1717c1..a18079c 100644 --- a/metrics-exporter-prometheus/Cargo.toml +++ b/metrics-exporter-prometheus/Cargo.toml @@ -20,8 +20,8 @@ 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 = { version = "0.13.0-alpha.1", path = "../metrics" } +metrics-util = { version = "0.4.0-alpha.1", path = "../metrics-util" } hdrhistogram = "7.1" parking_lot = "0.11" thiserror = "1.0" diff --git a/metrics-exporter-prometheus/src/lib.rs b/metrics-exporter-prometheus/src/lib.rs index ea4723b..ffeeda7 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -26,6 +26,9 @@ use tokio::{pin, runtime, select}; type PrometheusRegistry = Registry; type HdrHistogram = hdrhistogram::Histogram; +/// A type wrapper around the Inner struct of the Prometheus recorder. +pub type PrometheusHandle = Arc; + /// Errors that could occur while installing a Prometheus recorder/exporter. #[derive(ThisError, Debug)] pub enum Error { @@ -65,7 +68,8 @@ struct Snapshot { pub distributions: HashMap, Distribution>>, } -struct Inner { +/// Inner contains all of the data stored by the Prometheus Recorder. +pub struct Inner { registry: PrometheusRegistry, distributions: RwLock, Distribution>>>, quantiles: Vec, @@ -75,6 +79,7 @@ struct Inner { } impl Inner { + /// Returns a reference to the [`PrometheusRegistry`] this struct uses. pub fn registry(&self) -> &PrometheusRegistry { &self.registry } @@ -165,6 +170,7 @@ impl Inner { } } + /// Returns the metrics in Prometheus accepted String format. pub fn render(&self) -> String { let mut sorted_overrides = self .buckets_by_name @@ -334,9 +340,9 @@ pub struct PrometheusRecorder { } impl PrometheusRecorder { - /// Renders the Prometheus metrics in string format. - pub fn render(&self) -> String { - self.inner.render() + ///Returns a [`PrometheusHandle`] from the inner struct of this recorder. + pub fn handle(&self) -> PrometheusHandle { + self.inner.clone() } fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) { From e2ba57bfa63a08ec07a8c94f6fa2d994604a64e9 Mon Sep 17 00:00:00 2001 From: kilpatty Date: Fri, 30 Oct 2020 08:49:48 -0500 Subject: [PATCH 3/9] metrics-exporter-prometheus: move PrometheusHandle to struct. Eliminate now useless pub function doc comments --- metrics-exporter-prometheus/src/lib.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/metrics-exporter-prometheus/src/lib.rs b/metrics-exporter-prometheus/src/lib.rs index ffeeda7..22811bc 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -26,9 +26,6 @@ use tokio::{pin, runtime, select}; type PrometheusRegistry = Registry; type HdrHistogram = hdrhistogram::Histogram; -/// A type wrapper around the Inner struct of the Prometheus recorder. -pub type PrometheusHandle = Arc; - /// Errors that could occur while installing a Prometheus recorder/exporter. #[derive(ThisError, Debug)] pub enum Error { @@ -68,8 +65,7 @@ struct Snapshot { pub distributions: HashMap, Distribution>>, } -/// Inner contains all of the data stored by the Prometheus Recorder. -pub struct Inner { +struct Inner { registry: PrometheusRegistry, distributions: RwLock, Distribution>>>, quantiles: Vec, @@ -79,7 +75,6 @@ pub struct Inner { } impl Inner { - /// Returns a reference to the [`PrometheusRegistry`] this struct uses. pub fn registry(&self) -> &PrometheusRegistry { &self.registry } @@ -170,7 +165,6 @@ impl Inner { } } - /// Returns the metrics in Prometheus accepted String format. pub fn render(&self) -> String { let mut sorted_overrides = self .buckets_by_name @@ -342,7 +336,9 @@ pub struct PrometheusRecorder { impl PrometheusRecorder { ///Returns a [`PrometheusHandle`] from the inner struct of this recorder. pub fn handle(&self) -> PrometheusHandle { - self.inner.clone() + PrometheusHandle { + inner: self.inner.clone(), + } } fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) { @@ -355,6 +351,18 @@ impl PrometheusRecorder { } } +/// A wrapper around the Inner struct of the Prometheus recorder. +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, From 6e61eb493b0551fdef3222d6ec81b7518d864039 Mon Sep 17 00:00:00 2001 From: Sean Kilgarriff Date: Mon, 2 Nov 2020 07:17:47 -0600 Subject: [PATCH 4/9] Update metrics-exporter-prometheus/src/lib.rs Co-authored-by: Toby Lawrence --- metrics-exporter-prometheus/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics-exporter-prometheus/src/lib.rs b/metrics-exporter-prometheus/src/lib.rs index 22811bc..18d0243 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -439,7 +439,7 @@ impl PrometheusBuilder { /// 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() From 274ca273c47136653749db354f4afa4647d8c6d7 Mon Sep 17 00:00:00 2001 From: kilpatty Date: Mon, 2 Nov 2020 07:20:55 -0600 Subject: [PATCH 5/9] metrics-exporter-prometheus: drop feature gate on build, rename other build to build_with_exporter, and fix doc comments --- metrics-exporter-prometheus/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/metrics-exporter-prometheus/src/lib.rs b/metrics-exporter-prometheus/src/lib.rs index 18d0243..51cc77c 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -334,7 +334,7 @@ pub struct PrometheusRecorder { } impl PrometheusRecorder { - ///Returns a [`PrometheusHandle`] from the inner struct of this recorder. + /// Gets a [`PrometheusHandle`] to this recorder. pub fn handle(&self) -> PrometheusHandle { PrometheusHandle { inner: self.inner.clone(), @@ -351,7 +351,9 @@ impl PrometheusRecorder { } } -/// A wrapper around the Inner struct of the Prometheus recorder. +/// Handle to [`PrometheusRecorder`]. +/// +/// Useful for exposing a scrape endpoint on an existing HTTP/HTTPS server. pub struct PrometheusHandle { inner: Arc, } @@ -465,7 +467,6 @@ impl PrometheusBuilder { /// Builds the recorder and returns it. /// This function is only enabled when default features are not set. - #[cfg(not(feature = "tokio-exporter"))] pub fn build(self) -> Result { let inner = Arc::new(Inner { registry: Registry::new(), @@ -488,7 +489,7 @@ impl PrometheusBuilder { /// recorders, or needs to schedule the exporter to run in a particular way, this method /// provides the flexibility to do so. #[cfg(feature = "tokio-exporter")] - pub fn build( + pub fn build_with_exporter( self, ) -> Result< ( From fbd603582ede661970b448af0de7b399e8441894 Mon Sep 17 00:00:00 2001 From: Toby Lawrence Date: Mon, 2 Nov 2020 19:58:55 -0500 Subject: [PATCH 6/9] (cargo-release) version 0.1.0-alpha.7 --- metrics-exporter-prometheus/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics-exporter-prometheus/Cargo.toml b/metrics-exporter-prometheus/Cargo.toml index a18079c..0466d8f 100644 --- a/metrics-exporter-prometheus/Cargo.toml +++ b/metrics-exporter-prometheus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "metrics-exporter-prometheus" -version = "0.1.0-alpha.6" +version = "0.1.0-alpha.7" authors = ["Toby Lawrence "] edition = "2018" From 1b1c271531d5d4919ca1b06ea19b1f8acb52c844 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 10 Nov 2020 21:00:05 +0100 Subject: [PATCH 7/9] Trival docs typo --- metrics/src/key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics/src/key.rs b/metrics/src/key.rs index 6e86105..c0844bf 100644 --- a/metrics/src/key.rs +++ b/metrics/src/key.rs @@ -9,7 +9,7 @@ use core::{ /// Inner representation of [`Key`]. /// -/// While [`Key`] is the type that users will interact with via [`Recorder`][crate::Recorder`, +/// While [`Key`] is the type that users will interact with via [`Recorder`][crate::Recorder], /// [`KeyData`] is responsible for the actual storage of the name and label data. #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct KeyData { From 4fafc34869bffa0ffbe5b595d0c8098fd43c4fb7 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 10 Nov 2020 21:06:25 +0100 Subject: [PATCH 8/9] Add docs build to CI This should avoid accidentally breaking docs. --- .github/workflows/ci.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95bd4c4..0feed38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,23 @@ jobs: override: true - name: Run Tests run: cargo test + docs: + runs-on: ubuntu-latest + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v2 + - name: Install Rust Nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + components: rust-docs + - name: Check docs + uses: actions-rs/cargo@v1 + with: + command: doc + args: --workspace --no-deps bench: name: Bench ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -49,4 +66,4 @@ jobs: toolchain: 'stable' override: true - name: Run Benchmarks - run: cargo bench \ No newline at end of file + run: cargo bench From 01fcc020c743816eed397a476c85455c86ca4fd5 Mon Sep 17 00:00:00 2001 From: str4d Date: Wed, 11 Nov 2020 15:34:30 +0000 Subject: [PATCH 9/9] PrometheusBuilder::install: Build exporter in runtime context Closes https://github.com/metrics-rs/metrics/issues/122 --- metrics-exporter-prometheus/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metrics-exporter-prometheus/src/lib.rs b/metrics-exporter-prometheus/src/lib.rs index 033d864..bd0d63a 100644 --- a/metrics-exporter-prometheus/src/lib.rs +++ b/metrics-exporter-prometheus/src/lib.rs @@ -443,14 +443,14 @@ impl PrometheusBuilder { /// installing the recorder as the global recorder. #[cfg(feature = "tokio-exporter")] pub fn install(self) -> Result<(), Error> { - let (recorder, exporter) = self.build_with_exporter()?; - metrics::set_boxed_recorder(Box::new(recorder))?; - let mut runtime = runtime::Builder::new() .basic_scheduler() .enable_all() .build()?; + let (recorder, exporter) = runtime.enter(|| self.build_with_exporter())?; + metrics::set_boxed_recorder(Box::new(recorder))?; + thread::Builder::new() .name("metrics-exporter-prometheus-http".to_string()) .spawn(move || {