Merge branch 'main' into experiment/name-parts
This commit is contained in:
commit
db02cd80da
|
@ -35,6 +35,23 @@ jobs:
|
||||||
override: true
|
override: true
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: cargo test
|
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:
|
bench:
|
||||||
name: Bench ${{ matrix.os }}
|
name: Bench ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
@ -49,4 +66,7 @@ jobs:
|
||||||
toolchain: 'stable'
|
toolchain: 'stable'
|
||||||
override: true
|
override: true
|
||||||
- name: Run Benchmarks
|
- name: Run Benchmarks
|
||||||
run: cargo bench --all-features
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: bench
|
||||||
|
args: --all-features
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "metrics-exporter-prometheus"
|
name = "metrics-exporter-prometheus"
|
||||||
version = "0.1.0-alpha.6"
|
version = "0.1.0-alpha.7"
|
||||||
authors = ["Toby Lawrence <toby@nuclearfurnace.com>"]
|
authors = ["Toby Lawrence <toby@nuclearfurnace.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
@ -15,15 +15,21 @@ readme = "README.md"
|
||||||
categories = ["development-tools::debugging"]
|
categories = ["development-tools::debugging"]
|
||||||
keywords = ["metrics", "telemetry", "prometheus"]
|
keywords = ["metrics", "telemetry", "prometheus"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["tokio-exporter"]
|
||||||
|
tokio-exporter = ["hyper", "tokio"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
metrics = { version = "0.13.0-alpha.1", path = "../metrics" }
|
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"
|
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"
|
parking_lot = "0.11"
|
||||||
thiserror = "1.0"
|
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]
|
[dev-dependencies]
|
||||||
quanta = "0.6"
|
quanta = "0.6"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg), deny(broken_intra_doc_links))]
|
#![cfg_attr(docsrs, feature(doc_cfg), deny(broken_intra_doc_links))]
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
|
#[cfg(feature = "tokio-exporter")]
|
||||||
use hyper::{
|
use hyper::{
|
||||||
service::{make_service_fn, service_fn},
|
service::{make_service_fn, service_fn},
|
||||||
{Body, Error as HyperError, Response, Server},
|
{Body, Error as HyperError, Response, Server},
|
||||||
|
@ -16,9 +17,11 @@ use std::io;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
#[cfg(feature = "tokio-exporter")]
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::{collections::HashMap, time::SystemTime};
|
use std::{collections::HashMap, time::SystemTime};
|
||||||
use thiserror::Error as ThisError;
|
use thiserror::Error as ThisError;
|
||||||
|
#[cfg(feature = "tokio-exporter")]
|
||||||
use tokio::{pin, runtime, select};
|
use tokio::{pin, runtime, select};
|
||||||
|
|
||||||
type PrometheusRegistry = Registry<CompositeKey, Handle>;
|
type PrometheusRegistry = Registry<CompositeKey, Handle>;
|
||||||
|
@ -32,6 +35,7 @@ pub enum Error {
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
|
|
||||||
/// Binding/listening to the given address did not succeed.
|
/// Binding/listening to the given address did not succeed.
|
||||||
|
#[cfg(feature = "tokio-exporter")]
|
||||||
#[error("failed to bind to given listen address: {0}")]
|
#[error("failed to bind to given listen address: {0}")]
|
||||||
Hyper(#[from] HyperError),
|
Hyper(#[from] HyperError),
|
||||||
|
|
||||||
|
@ -331,6 +335,13 @@ pub struct PrometheusRecorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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>) {
|
fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) {
|
||||||
if let Some(description) = description {
|
if let Some(description) = description {
|
||||||
let mut descriptions = self.inner.descriptions.write();
|
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<Inner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
/// Builder for creating and installing a Prometheus recorder/exporter.
|
||||||
pub struct PrometheusBuilder {
|
pub struct PrometheusBuilder {
|
||||||
listen_address: SocketAddr,
|
listen_address: SocketAddr,
|
||||||
|
@ -416,15 +441,16 @@ impl PrometheusBuilder {
|
||||||
///
|
///
|
||||||
/// An error will be returned if there's an issue with creating the HTTP server or with
|
/// An error will be returned if there's an issue with creating the HTTP server or with
|
||||||
/// installing the recorder as the global recorder.
|
/// installing the recorder as the global recorder.
|
||||||
|
#[cfg(feature = "tokio-exporter")]
|
||||||
pub fn install(self) -> Result<(), Error> {
|
pub fn install(self) -> Result<(), Error> {
|
||||||
let (recorder, exporter) = self.build()?;
|
|
||||||
metrics::set_boxed_recorder(Box::new(recorder))?;
|
|
||||||
|
|
||||||
let mut runtime = runtime::Builder::new()
|
let mut runtime = runtime::Builder::new()
|
||||||
.basic_scheduler()
|
.basic_scheduler()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
|
let (recorder, exporter) = runtime.enter(|| self.build_with_exporter())?;
|
||||||
|
metrics::set_boxed_recorder(Box::new(recorder))?;
|
||||||
|
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("metrics-exporter-prometheus-http".to_string())
|
.name("metrics-exporter-prometheus-http".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
|
@ -441,13 +467,31 @@ impl PrometheusBuilder {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the recorder and returns it.
|
||||||
|
/// This function is only enabled when default features are not set.
|
||||||
|
pub fn build(self) -> Result<PrometheusRecorder, Error> {
|
||||||
|
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.
|
/// Builds the recorder and exporter and returns them both.
|
||||||
///
|
///
|
||||||
/// In most cases, users should prefer to use [`PrometheusBuilder::install`] to create and
|
/// 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
|
/// 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
|
/// recorders, or needs to schedule the exporter to run in a particular way, this method
|
||||||
/// provides the flexibility to do so.
|
/// provides the flexibility to do so.
|
||||||
pub fn build(
|
#[cfg(feature = "tokio-exporter")]
|
||||||
|
pub fn build_with_exporter(
|
||||||
self,
|
self,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
|
|
|
@ -87,7 +87,7 @@ impl fmt::Display for NameParts {
|
||||||
|
|
||||||
/// Inner representation of [`Key`].
|
/// 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.
|
/// [`KeyData`] is responsible for the actual storage of the name and label data.
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
pub struct KeyData {
|
pub struct KeyData {
|
||||||
|
|
Loading…
Reference in New Issue