chore!: replace prometheus with metrics

As part of the overall modernization of this application, this commit
replaces the prometheus crate with the generic metrics facade crate, and
the metrics_exporter_prometheus crate for exporting the metrics to
prometheus.

This also removes some useless http metrics that were cargo-culted in
from the prometheus crate example.

BREAKING CHANGE: http metrics are removed by this change
This commit is contained in:
Jan Christian Grünhage 2022-03-17 14:58:38 +01:00
parent 490c2031d2
commit 854ddced3a
6 changed files with 308 additions and 98 deletions

270
Cargo.lock generated
View file

@ -2,6 +2,17 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
@ -39,6 +50,15 @@ dependencies = [
"syn",
]
[[package]]
name = "atomic-shim"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67cd4b51d303cf3501c301e8125df442128d3c6d7c69f71b27833d253de47e77"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -106,6 +126,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "bytes"
version = "1.0.1"
@ -146,6 +172,30 @@ dependencies = [
"vec_map",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "darling"
version = "0.13.1"
@ -309,6 +359,15 @@ dependencies = [
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
version = "0.1.18"
@ -387,6 +446,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.9"
@ -402,6 +471,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "js-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -433,6 +511,15 @@ dependencies = [
"serde",
]
[[package]]
name = "mach"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
dependencies = [
"libc",
]
[[package]]
name = "matches"
version = "0.1.9"
@ -451,6 +538,67 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "metrics"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e52eb6380b6d2a10eb3434aec0885374490f5b82c8aaf5cd487a183c98be834"
dependencies = [
"ahash",
"metrics-macros",
]
[[package]]
name = "metrics-exporter-prometheus"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b93b470b04c005178058e18ac8bb2eb3fda562cf87af5ea05ba8d44190d458c"
dependencies = [
"indexmap",
"metrics",
"metrics-util",
"parking_lot",
"quanta",
"thiserror",
]
[[package]]
name = "metrics-macros"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49e30813093f757be5cf21e50389a24dc7dbb22c49f23b7e8f51d69b508a5ffa"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "metrics-util"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "107a38013e91c04ddf31826b0d0dcc2e0d4ebedded8234cc0dc2b7bbd0c121e8"
dependencies = [
"atomic-shim",
"crossbeam-epoch",
"crossbeam-utils",
"hashbrown",
"metrics",
"num_cpus",
"parking_lot",
"quanta",
"sketches-ddsketch",
]
[[package]]
name = "mime"
version = "0.3.16"
@ -517,6 +665,12 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "parking_lot"
version = "0.11.1"
@ -560,9 +714,9 @@ dependencies = [
"fern",
"futures",
"futures-util",
"lazy_static",
"log",
"prometheus",
"metrics",
"metrics-exporter-prometheus",
"serde",
"serde_with",
"tokio",
@ -630,26 +784,21 @@ dependencies = [
]
[[package]]
name = "prometheus"
version = "0.12.0"
name = "quanta"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c"
checksum = "20afe714292d5e879d8b12740aa223c6a88f118af41870e8b6196e39a02238a8"
dependencies = [
"cfg-if",
"fnv",
"lazy_static",
"memchr",
"parking_lot",
"protobuf",
"thiserror",
"crossbeam-utils",
"libc",
"mach",
"once_cell",
"raw-cpuid",
"wasi",
"web-sys",
"winapi",
]
[[package]]
name = "protobuf"
version = "2.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45604fc7a88158e7d514d8e22e14ac746081e7a70d7690074dd0029ee37458d6"
[[package]]
name = "quote"
version = "1.0.9"
@ -699,6 +848,15 @@ dependencies = [
"rand_core",
]
[[package]]
name = "raw-cpuid"
version = "10.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "929f54e29691d4e6a9cc558479de70db7aa3d98cd6fe7ab86d7507aa2886b9d2"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_syscall"
version = "0.2.6"
@ -792,6 +950,12 @@ dependencies = [
"syn",
]
[[package]]
name = "sketches-ddsketch"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a77a8fd93886010f05e7ea0720e569d6d16c65329dbe3ec033bbbccccb017b"
[[package]]
name = "slab"
version = "0.4.3"
@ -1039,6 +1203,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.0"
@ -1055,6 +1225,70 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "web-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -9,9 +9,7 @@ edition = "2018"
description = "Pings configured hosts in a configurable intervals and exposes metrics for prometheus."
[dependencies]
prometheus = "0.12"
toml = "0.5"
lazy_static = "1"
futures = "0.3"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] }
clap = "2"
@ -25,3 +23,5 @@ futures-util = "0.3"
anyhow = "1"
async-anyhow-logger = "0.1"
axum = "0.4.8"
metrics = "0.18.1"
metrics-exporter-prometheus = { version = "0.9.0", default-features = false }

View file

@ -20,10 +20,17 @@
use anyhow::{Context, Result};
use clap::{clap_app, crate_authors, crate_description, crate_name, crate_version};
use log::info;
use metrics::{describe_histogram, register_histogram, Unit};
use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle};
use serde::Deserialize;
use serde_with::{serde_as, DurationMilliSeconds};
use std::{collections::HashMap, time::Duration};
pub(crate) struct App {
pub(crate) config: Config,
pub(crate) handle: PrometheusHandle,
}
#[derive(Deserialize, Clone)]
pub(crate) struct Config {
pub(crate) listener: std::net::SocketAddr,
@ -97,14 +104,37 @@ fn read_config(path: &str) -> Result<Config> {
Ok(toml::from_str(&config_file_content).context("Couldn't parse config file")?)
}
pub(crate) fn setup_app() -> Result<Config> {
pub(crate) fn setup_app() -> Result<App> {
let clap = setup_clap();
let config_path = clap
.value_of("config")
.context("Got no config file. clap should've catched this")?;
let config = read_config(config_path).context("Couldn't read config file!")?;
setup_fern(determine_level(clap.occurrences_of("v"), config.log.level));
Ok(config)
let handle = setup_prometheus(&config)?;
Ok(App { config, handle })
}
pub(crate) fn setup_prometheus(config: &Config) -> Result<PrometheusHandle> {
let handle = PrometheusBuilder::new()
.set_buckets_for_metric(Matcher::Full("ping_rtt_milliseconds".into()), &vec![
0.5, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 50.0, 75.0, 100.0, 150.0, 200.0, 250.0, 300.0,
350.0, 400.0, 450.0, 500.0, 550.0, 600.0, 650.0, 700.0, 750.0, 800.0, 900.0, 1000.0,
1250.0, 1500.0, 1750.0, 2000.0,
])?
.install_recorder()?;
for target in config.ping.hosts.keys() {
register_histogram!("ping_rtt_milliseconds", "target" => target.to_string());
}
describe_histogram!(
"ping_rtt_milliseconds",
Unit::Milliseconds,
"The ping round trip time in milliseconds"
);
Ok(handle)
}
fn determine_level(verbose_occurrences: u64, config_level: log::LevelFilter) -> log::LevelFilter {

View file

@ -24,16 +24,18 @@ mod config;
mod metrics;
mod ping;
use config::setup_app;
use metrics::start_serving_metrics;
use ping::start_pinging_hosts;
use crate::{
config::{setup_app, App},
metrics::start_serving_metrics,
ping::start_pinging_hosts,
};
#[tokio::main]
async fn main() -> Result<()> {
let config = setup_app()?;
let App { config, handle } = setup_app()?;
let ping_fut = catch(start_pinging_hosts(&config));
let serve_fut = catch(start_serving_metrics(&config));
let serve_fut = catch(start_serving_metrics(&config, handle));
futures::pin_mut!(ping_fut);
futures::pin_mut!(serve_fut);

View file

@ -19,60 +19,23 @@
********************************************************************************/
use crate::config::Config;
use anyhow::Result;
use axum::body::Body;
use axum::http::{Response, StatusCode};
use axum::{http::header::CONTENT_TYPE, response::IntoResponse, routing::get, Router, Server};
use lazy_static::lazy_static;
use axum::{response::IntoResponse, routing::get, Router, Server};
use log::info;
use prometheus::*;
use prometheus::{Counter, Gauge, HistogramVec, TextEncoder};
use metrics_exporter_prometheus::PrometheusHandle;
lazy_static! {
static ref HTTP_COUNTER: Counter = register_counter!(opts!(
"http_requests_total",
"Total number of HTTP requests made.",
labels! {"handler" => "all",}
))
.unwrap();
static ref HTTP_BODY_GAUGE: Gauge = register_gauge!(opts!(
"http_response_size_bytes",
"The HTTP response sizes in bytes.",
labels! {"handler" => "all",}
))
.unwrap();
static ref HTTP_REQ_HISTOGRAM: HistogramVec = register_histogram_vec!(
"http_request_duration_seconds",
"The HTTP request latencies in seconds.",
&["handler"]
)
.unwrap();
async fn metrics(handle: PrometheusHandle) -> impl IntoResponse {
handle.render()
}
async fn serve_metrics() -> impl IntoResponse {
let encoder = TextEncoder::new();
HTTP_COUNTER.inc();
let timer = HTTP_REQ_HISTOGRAM.with_label_values(&["all"]).start_timer();
let metric_families = prometheus::gather();
let mut buffer = vec![];
encoder.encode(&metric_families, &mut buffer).unwrap();
HTTP_BODY_GAUGE.set(buffer.len() as f64);
let response = Response::builder()
.status(StatusCode::OK)
.header(CONTENT_TYPE, encoder.format_type())
.body(Body::from(buffer))
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR);
timer.observe_duration();
response
}
pub(crate) async fn start_serving_metrics(config: &Config) -> Result<()> {
pub(crate) async fn start_serving_metrics(config: &Config, handle: PrometheusHandle) -> Result<()> {
let app = Router::new()
.route("/metrics", get(serve_metrics))
.route(
"/metrics",
get({
let handle = handle.clone();
move || metrics(handle)
}),
)
.route("/health", get(|| async { "" }));
let serve_future = Server::bind(&config.listener).serve(app.into_make_service());
info!("Listening on {}", &config.listener);

View file

@ -20,27 +20,12 @@
use crate::config::Config;
use anyhow::{Context, Result};
use async_anyhow_logger::catch;
use lazy_static::lazy_static;
use log::{info, trace};
use prometheus::*;
use metrics::histogram;
use std::net::IpAddr;
use std::time::Duration;
use tokio_icmp_echo::{PingFuture, Pinger};
lazy_static! {
static ref PING_HISTOGRAM: HistogramVec = register_histogram_vec!(
"ping_rtt_milliseconds",
"The ping round trip time in milliseconds",
&["target"],
vec![
0.5, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 50.0, 75.0, 100.0, 150.0, 200.0, 250.0, 300.0,
350.0, 400.0, 450.0, 500.0, 550.0, 600.0, 650.0, 700.0, 750.0, 800.0, 900.0, 1000.0,
1250.0, 1500.0, 1750.0, 2000.0
]
)
.unwrap();
}
pub(crate) async fn start_pinging_hosts(config: &Config) -> Result<()> {
let pinger = Pinger::new().await.context("Couldn't create pinger")?;
let mut handles = vec![];
@ -78,15 +63,11 @@ async fn handle_ping_result(result: PingFuture, host: String, timeout: Duration)
Some(time) => {
let ms = time.as_millis();
trace!("Received pong from {} after {} ms", &host, &ms);
PING_HISTOGRAM
.with_label_values(&[&host])
.observe(ms as f64);
histogram!("ping_rtt_milliseconds", ms as f64, "target" => host);
}
None => {
trace!("Received no response from {} within timeout", &host);
PING_HISTOGRAM
.with_label_values(&[&host])
.observe(timeout.as_millis() as f64);
histogram!("ping_rtt_milliseconds", timeout.as_millis() as f64, "target" => host);
}
};