From bdeb6ef7bf898b50eb3a742219a00c735cde65ae Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Tue, 22 Sep 2026 00:36:00 +0900 Subject: [PATCH] gitmirror: basic metrics Signed-off-by: Seongmin Lee --- Cargo.lock | 98 ++++- Cargo.toml | 3 + docker-compose.yml | 1 + gitmirror/crates/gitmirror-xrpc/Cargo.toml | 2 + gitmirror/crates/gitmirror-xrpc/src/error.rs | 8 +- gitmirror/crates/gitmirror-xrpc/src/lib.rs | 2 + .../crates/gitmirror-xrpc/src/metrics.rs | 150 ++++++++ .../crates/gitmirror-xrpc/src/routes/git.rs | 15 + gitmirror/crates/gitmirror/src/config.rs | 20 +- gitmirror/crates/gitmirror/src/main.rs | 39 +- nix/Cargo.nix | 352 +++++++++++++++++- 11 files changed, 666 insertions(+), 24 deletions(-) create mode 100644 gitmirror/crates/gitmirror-xrpc/src/metrics.rs diff --git a/Cargo.lock b/Cargo.lock index c4f5b8b8b..51b6536fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2321,6 +2321,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "evmap" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8874945f036109c72242964c1174cf99434e30cfa45bf45fedc983f50046f8" +dependencies = [ + "hashbag", + "left-right", + "smallvec", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -2803,6 +2814,8 @@ dependencies = [ "jacquard-identity", "lexicons", "line-numbers", + "metrics", + "metrics-exporter-prometheus", "quick_cache", "reqwest 0.13.1", "rustc-hash", @@ -3944,6 +3957,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbag" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7040a10f52cba493ddb09926e15d10a9d8a28043708a405931fe4c6f19fac064" + [[package]] name = "hashbrown" version = "0.14.5" @@ -5730,6 +5749,17 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "left-right" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bc015ded5d9b3054dbbdb63332cdd6ee42352ccef19e911e25117490e2f48ee" +dependencies = [ + "crossbeam-utils", + "loom", + "slab", +] + [[package]] name = "levenshtein_automata" version = "0.2.1" @@ -5980,6 +6010,48 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metrics" +version = "0.24.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89550ee9f79e88fef3119de263694973a8adb26c21d75322164fb8c493039fe2" +dependencies = [ + "portable-atomic", + "rapidhash", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db0d8f1fc9e62caebd0319e11eaec5822b0186c171568f0480b46a0137f9108" +dependencies = [ + "base64", + "evmap", + "indexmap", + "metrics", + "metrics-util", + "quanta", + "thiserror 2.0.18", +] + +[[package]] +name = "metrics-util" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96f8722f8562635f92f8ed992f26df0532266eb03d5202607c20c0d7e9745e13" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.16.1", + "metrics", + "quanta", + "rand 0.9.4", + "rand_xoshiro", + "rapidhash", + "sketches-ddsketch 0.3.1", +] + [[package]] name = "miette" version = "7.6.0" @@ -7281,6 +7353,24 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "rustversion", +] + [[package]] name = "raw-cpuid" version = "11.6.0" @@ -8368,6 +8458,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" +[[package]] +name = "sketches-ddsketch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" + [[package]] name = "sketches-ddsketch" version = "0.4.0" @@ -8692,7 +8788,7 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "sketches-ddsketch", + "sketches-ddsketch 0.4.0", "smallvec", "tantivy-bitpacker", "tantivy-columnar", diff --git a/Cargo.toml b/Cargo.toml index 0f83fbdf5..09a24c391 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,6 +202,9 @@ tikv-jemalloc-ctl = "0.7" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json"] } +metrics = "0.24" +metrics-exporter-prometheus = { version = "0.18", default-features = false } + thiserror = "2" confique = { version = "0.4", default-features = false, features = ["toml"] } diff --git a/docker-compose.yml b/docker-compose.yml index a492a3b1e..13077d49e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -335,6 +335,7 @@ services: environment: RUST_LOG: gitmirror=debug GITMIRROR_BIND: 0.0.0.0:9001 + GITMIRROR_METRICS_BIND: 0.0.0.0:9091 GITMIRROR_SCAN_PATH: /data/repos GITMIRROR_PLC_URL: https://plc.tngl.boltless.dev GITMIRROR_SERVICE_DID: did:web:mirror.tngl.boltless.dev diff --git a/gitmirror/crates/gitmirror-xrpc/Cargo.toml b/gitmirror/crates/gitmirror-xrpc/Cargo.toml index a3ca75c0c..26d17d047 100644 --- a/gitmirror/crates/gitmirror-xrpc/Cargo.toml +++ b/gitmirror/crates/gitmirror-xrpc/Cargo.toml @@ -19,6 +19,8 @@ chrono = { workspace = true } jacquard-axum = { workspace = true } jacquard-common = { workspace = true } jacquard-identity = { workspace = true } +metrics = { workspace = true } +metrics-exporter-prometheus = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true, features = ["net", "rt-multi-thread", "sync", "time"] } thiserror = { workspace = true } diff --git a/gitmirror/crates/gitmirror-xrpc/src/error.rs b/gitmirror/crates/gitmirror-xrpc/src/error.rs index 638df661a..9668069f2 100644 --- a/gitmirror/crates/gitmirror-xrpc/src/error.rs +++ b/gitmirror/crates/gitmirror-xrpc/src/error.rs @@ -6,6 +6,9 @@ use reqwest::StatusCode; use serde_json::json; use tracing::error; +#[derive(Clone, Copy)] +pub(crate) struct ErrorKind(pub(crate) &'static str); + #[derive(Debug)] pub(crate) enum XrpcError { InvalidRequest(String), @@ -96,7 +99,10 @@ impl IntoResponse for XrpcError { ) } }; - (status, Json(json!({ "error": error, "message": message }))).into_response() + let mut response = + (status, Json(json!({ "error": error, "message": message }))).into_response(); + response.extensions_mut().insert(ErrorKind(error)); + response } } diff --git a/gitmirror/crates/gitmirror-xrpc/src/lib.rs b/gitmirror/crates/gitmirror-xrpc/src/lib.rs index 9b12fcc7d..98723fb3c 100644 --- a/gitmirror/crates/gitmirror-xrpc/src/lib.rs +++ b/gitmirror/crates/gitmirror-xrpc/src/lib.rs @@ -3,6 +3,7 @@ mod diff; mod error; mod git_transport; mod merge; +pub mod metrics; mod routes; use std::{path::PathBuf, sync::Arc}; @@ -80,6 +81,7 @@ pub fn router(state: AppState) -> Router { .route("/xrpc/sh.tangled.git.temp2.mergeCheck", get(git::merge_check)) .route("/xrpc/sh.tangled.git.mergeCommit", post(git::merge_commit)) .route("/xrpc/org.tangled.temp.git.deleteBranch", post(git::delete_branch)) + .layer(axum::middleware::from_fn(metrics::metrics_middleware)) .with_state(state) } diff --git a/gitmirror/crates/gitmirror-xrpc/src/metrics.rs b/gitmirror/crates/gitmirror-xrpc/src/metrics.rs new file mode 100644 index 000000000..9a5352584 --- /dev/null +++ b/gitmirror/crates/gitmirror-xrpc/src/metrics.rs @@ -0,0 +1,150 @@ +use axum::{ + Router, + extract::MatchedPath, + http::{Request, StatusCode}, + middleware::Next, + response::{IntoResponse, Response}, + routing::get, +}; +use metrics::{counter, gauge, histogram}; +use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle}; +use std::sync::OnceLock; +use std::time::Instant; +use tracing::Instrument as _; + +use crate::error::ErrorKind; + +static PROMETHEUS_HANDLE: OnceLock = OnceLock::new(); + +pub fn init_metrics() -> PrometheusHandle { + let builder = PrometheusBuilder::new(); + let handle = builder + .install_recorder() + .expect("failed to install Prometheus recorder"); + + PROMETHEUS_HANDLE.set(handle.clone()).ok(); + describe_metrics(); + + handle +} + +fn describe_metrics() { + metrics::describe_counter!( + "gitmirror_xrpc_requests_total", + "Total number of XRPC requests" + ); + metrics::describe_histogram!( + "gitmirror_xrpc_duration_seconds", + "XRPC request duration in seconds" + ); + metrics::describe_gauge!( + "gitmirror_xrpc_in_flight", + "Number of XRPC requests currently being handled" + ); +} + +pub fn router() -> Router { + Router::new().route("/metrics", get(metrics_handler)) +} + +pub async fn metrics_handler() -> impl IntoResponse { + match PROMETHEUS_HANDLE.get() { + Some(handle) => { + handle.run_upkeep(); + ( + StatusCode::OK, + [("content-type", "text/plain; version=0.0.4")], + handle.render(), + ) + } + None => ( + StatusCode::INTERNAL_SERVER_ERROR, + [("content-type", "text/plain")], + "Metrics not initialized".to_string(), + ), + } +} + +struct InFlightGuard { + method: String, + path: String, +} + +impl Drop for InFlightGuard { + fn drop(&mut self) { + gauge!( + "gitmirror_xrpc_in_flight", + "method" => self.method.clone(), + "path" => self.path.clone() + ) + .decrement(1); + } +} + +pub async fn metrics_middleware(request: Request, next: Next) -> Response { + let start = Instant::now(); + let method = request.method().to_string(); + let path = normalize_path(&request); + + let span = tracing::info_span!( + "xrpc", + method = %method, + path = %path, + repo = tracing::field::Empty, + base_repo = tracing::field::Empty, + status = tracing::field::Empty, + error = tracing::field::Empty, + duration_ms = tracing::field::Empty, + ); + + gauge!( + "gitmirror_xrpc_in_flight", + "method" => method.clone(), + "path" => path.clone() + ) + .increment(1); + let _in_flight = InFlightGuard { + method: method.clone(), + path: path.clone(), + }; + + let response = next.run(request).instrument(span.clone()).await; + + let duration = start.elapsed().as_secs_f64(); + let status = response.status().as_u16().to_string(); + let error = response + .extensions() + .get::() + .map_or("none", |kind| kind.0); + + counter!( + "gitmirror_xrpc_requests_total", + "method" => method.clone(), + "path" => path.clone(), + "status" => status.clone(), + "error" => error + ) + .increment(1); + + histogram!( + "gitmirror_xrpc_duration_seconds", + "method" => method, + "path" => path + ) + .record(duration); + + span.record("status", status.as_str()); + span.record("error", error); + span.record("duration_ms", duration * 1e3); + tracing::info!(parent: &span, "xrpc served"); + + response +} + +fn normalize_path(request: &Request) -> String { + request + .extensions() + .get::() + .map(|matched| matched.as_str().to_string()) + .unwrap_or_else(|| "unknown".to_string()) +} diff --git a/gitmirror/crates/gitmirror-xrpc/src/routes/git.rs b/gitmirror/crates/gitmirror-xrpc/src/routes/git.rs index fabeac140..4c1c0a2f9 100644 --- a/gitmirror/crates/gitmirror-xrpc/src/routes/git.rs +++ b/gitmirror/crates/gitmirror-xrpc/src/routes/git.rs @@ -457,6 +457,7 @@ pub(crate) async fn get_blame( State(state): State, ExtractXrpc(args): ExtractXrpc, ) -> Result, XrpcError> { + tracing::Span::current().record("repo", args.repo.as_str()); let repo_path = state.layout.repo_path(&args.repo); let deadline = Instant::now() + BLAME_TIMEOUT; let task = tokio::task::spawn_blocking(move || { @@ -500,6 +501,9 @@ pub(crate) async fn get_diff( State(state): State, ExtractXrpc(args): ExtractXrpc, ) -> Result, XrpcError> { + let span = tracing::Span::current(); + span.record("repo", args.head_repo.as_str()); + span.record("base_repo", args.base_repo.as_str()); let scratch = state .layout .open_scratch(&[&args.head_repo, &args.base_repo])?; @@ -543,6 +547,9 @@ pub(crate) async fn get_interdiff( State(state): State, ExtractXrpc(args): ExtractXrpc, ) -> Result, XrpcError> { + let span = tracing::Span::current(); + span.record("repo", args.head_repo.as_str()); + span.record("base_repo", args.base_repo.as_str()); let from_base_id = ObjectId::from_hex(args.base_commit1.as_bytes()) .map_err(|e| XrpcError::InvalidRequest(e.to_string()))?; let from_head_id = ObjectId::from_hex(args.base_commit2.as_bytes()) @@ -678,6 +685,7 @@ pub(crate) async fn list_commits( State(state): State, ExtractXrpc(args): ExtractXrpc, ) -> Result, XrpcError> { + tracing::Span::current().record("repo", args.repo.as_str()); let path = state.layout.repo_path(&args.repo); let repo = gix::open(path).map_err(|e| XrpcError::RepoNotFound { detail: e.to_string(), @@ -700,6 +708,9 @@ pub(crate) async fn merge_check( State(state): State, ExtractXrpc(params): ExtractXrpc, ) -> Result, XrpcError> { + let span = tracing::Span::current(); + span.record("repo", params.target_repo.as_str()); + span.record("base_repo", params.source_repo.as_str()); let scratch = state .layout .open_scratch(&[¶ms.target_repo, ¶ms.source_repo])?; @@ -719,6 +730,9 @@ pub(crate) async fn merge_commit( ExtractAnyServiceAuth(auth, token): ExtractAnyServiceAuth, ExtractXrpc(input): ExtractXrpc, ) -> Result, XrpcError> { + let span = tracing::Span::current(); + span.record("repo", input.target.repo.as_str()); + span.record("base_repo", input.source.repo.as_str()); require_push_token(&auth)?; // 1. validate inputs @@ -820,6 +834,7 @@ pub(crate) async fn delete_branch( ExtractAnyServiceAuth(auth, token): ExtractAnyServiceAuth, ExtractXrpc(input): ExtractXrpc, ) -> Result, XrpcError> { + tracing::Span::current().record("repo", input.repo.as_str()); require_push_token(&auth)?; let refname = head_ref(input.branch.as_str())?; diff --git a/gitmirror/crates/gitmirror/src/config.rs b/gitmirror/crates/gitmirror/src/config.rs index a353500b0..51965fabc 100644 --- a/gitmirror/crates/gitmirror/src/config.rs +++ b/gitmirror/crates/gitmirror/src/config.rs @@ -33,6 +33,15 @@ pub struct ServerConfig { default = ["127.0.0.1:9001", "[::1]:9001"] )] pub binds: Vec, + + /// Addresses the Prometheus metrics endpoint listens on. When using as an env var, + /// comma-separated; set it empty to disable the endpoint entirely. + #[config( + env = "GITMIRROR_METRICS_BIND", + parse_env = parse_optional_binds, + default = ["127.0.0.1:9091"] + )] + pub metrics_binds: Vec, } // TODO: share codes with bobbin @@ -45,13 +54,16 @@ pub enum BindParseError { Invalid(String, std::net::AddrParseError), } -fn parse_binds(raw: &str) -> Result, BindParseError> { - let addrs: Vec = raw - .split(',') +fn parse_optional_binds(raw: &str) -> Result, BindParseError> { + raw.split(',') .map(str::trim) .filter(|s| !s.is_empty()) .map(|s| SocketAddr::from_str(s).map_err(|e| BindParseError::Invalid(s.to_owned(), e))) - .collect::>()?; + .collect() +} + +fn parse_binds(raw: &str) -> Result, BindParseError> { + let addrs = parse_optional_binds(raw)?; if addrs.is_empty() { return Err(BindParseError::Empty); } diff --git a/gitmirror/crates/gitmirror/src/main.rs b/gitmirror/crates/gitmirror/src/main.rs index b0c4f17ad..f33c54ddb 100644 --- a/gitmirror/crates/gitmirror/src/main.rs +++ b/gitmirror/crates/gitmirror/src/main.rs @@ -117,23 +117,41 @@ async fn serve(cfg: MirrorConfig) -> anyhow::Result<()> { // TODO: add debug routes let binds = cfg.server.binds.clone(); - let bind_display = binds + tracing::info!(binds = %bind_display(&binds), "gitmirror listening"); + let metrics_binds = cfg.server.metrics_binds.clone(); + if metrics_binds.is_empty() { + tracing::info!("metrics endpoint disabled"); + } else { + gitmirror_xrpc::metrics::init_metrics(); + tracing::info!(binds = %bind_display(&metrics_binds), "gitmirror metrics listening"); + } + + let mut targets: Vec<(SocketAddr, axum::Router)> = + binds.into_iter().map(|addr| (addr, app.clone())).collect(); + targets.extend( + metrics_binds + .into_iter() + .map(|addr| (addr, gitmirror_xrpc::metrics::router())), + ); + + serve_all(targets).await +} + +fn bind_display(binds: &[SocketAddr]) -> String { + binds .iter() .map(|bind| bind.to_string()) .collect::>() - .join(","); - tracing::info!(binds = %bind_display, "gitmirror listening"); - - serve_all(binds, app).await + .join(",") } -async fn serve_all(binds: Vec, app: axum::Router) -> anyhow::Result<()> { - let listeners = binds +async fn serve_all(targets: Vec<(SocketAddr, axum::Router)>) -> anyhow::Result<()> { + let listeners = targets .into_iter() - .map(|addr| { + .map(|(addr, app)| { let listener = bind_listener(addr).with_context(|| format!("bind {addr}"))?; tracing::info!(%addr, "gitmirror listener bound"); - anyhow::Ok(listener) + anyhow::Ok((listener, app)) }) .collect::>>()?; @@ -145,8 +163,7 @@ async fn serve_all(binds: Vec, app: axum::Router) -> anyhow::Result< trigger.cancel(); }); - let result = futures::future::try_join_all(listeners.into_iter().map(|listener| { - let app = app.clone(); + let result = futures::future::try_join_all(listeners.into_iter().map(|(listener, app)| { let cancel = cancel.clone(); async move { axum::serve(listener, app) diff --git a/nix/Cargo.nix b/nix/Cargo.nix index 8315a4860..7d408e799 100644 --- a/nix/Cargo.nix +++ b/nix/Cargo.nix @@ -8251,6 +8251,38 @@ rec { }; resolvedDefaultFeatures = [ "std" ]; }; + "evmap" = rec { + crateName = "evmap"; + version = "11.0.0"; + edition = "2018"; + sha256 = "1y2603sq7jgdbzs5p96g617476fgfh8lr5j24b3hjq83bya7920v"; + authors = [ + "Jon Gjengset " + ]; + dependencies = [ + { + name = "hashbag"; + packageId = "hashbag"; + } + { + name = "left-right"; + packageId = "left-right"; + } + { + name = "smallvec"; + packageId = "smallvec"; + } + ]; + features = { + "amortize" = [ "indexmap-amortized" "hashbag/amortize" ]; + "eviction" = [ "indexed" "rand" ]; + "indexed" = [ "indexmap" ]; + "indexmap" = [ "dep:indexmap" ]; + "indexmap-amortized" = [ "dep:indexmap-amortized" ]; + "rand" = [ "dep:rand" ]; + }; + resolvedDefaultFeatures = [ "default" ]; + }; "fallible-iterator" = rec { crateName = "fallible-iterator"; version = "0.3.0"; @@ -9809,6 +9841,15 @@ rec { name = "line-numbers"; packageId = "line-numbers"; } + { + name = "metrics"; + packageId = "metrics"; + } + { + name = "metrics-exporter-prometheus"; + packageId = "metrics-exporter-prometheus"; + usesDefaultFeatures = false; + } { name = "quick_cache"; packageId = "quick_cache"; @@ -13741,6 +13782,20 @@ rec { ]; }; + "hashbag" = rec { + crateName = "hashbag"; + version = "0.1.13"; + edition = "2018"; + sha256 = "0r60z8cnyk7y65cl12kh8f0a5n5921fy29lrn3fr796ba87s2h3h"; + authors = [ + "Jon Gjengset " + ]; + features = { + "amortize" = [ "griddle" ]; + "griddle" = [ "dep:griddle" ]; + "serde" = [ "dep:serde" ]; + }; + }; "hashbrown 0.14.5" = rec { crateName = "hashbrown"; version = "0.14.5"; @@ -17782,6 +17837,10 @@ rec { name = "knot-cache"; packageId = "knot-cache"; } + { + name = "knot-record"; + packageId = "knot-record"; + } { name = "knot-runtime"; packageId = "knot-runtime"; @@ -19369,6 +19428,11 @@ rec { name = "serde_ipld_dagcbor"; packageId = "serde_ipld_dagcbor"; } + { + name = "serde_json"; + packageId = "serde_json"; + features = [ "raw_value" ]; + } { name = "thiserror"; packageId = "thiserror 2.0.18"; @@ -19383,11 +19447,6 @@ rec { name = "proptest"; packageId = "proptest"; } - { - name = "serde_json"; - packageId = "serde_json"; - features = [ "raw_value" ]; - } { name = "tempfile"; packageId = "tempfile"; @@ -20541,6 +20600,33 @@ rec { }; resolvedDefaultFeatures = [ "spin" "spin_no_std" ]; }; + "left-right" = rec { + crateName = "left-right"; + version = "0.11.8"; + edition = "2018"; + sha256 = "1vj85w74j5siw88yj6ggri927r3fvln36qyvpd6hbcyrspg1bh4b"; + libName = "left_right"; + authors = [ + "Jon Gjengset " + ]; + dependencies = [ + { + name = "crossbeam-utils"; + packageId = "crossbeam-utils"; + usesDefaultFeatures = false; + } + { + name = "loom"; + packageId = "loom"; + target = { target, features }: (target."loom" or false); + } + { + name = "slab"; + packageId = "slab"; + } + ]; + + }; "levenshtein_automata" = rec { crateName = "levenshtein_automata"; version = "0.2.1"; @@ -21236,6 +21322,203 @@ rec { }; resolvedDefaultFeatures = [ "default" ]; }; + "metrics" = rec { + crateName = "metrics"; + version = "0.24.6"; + edition = "2018"; + sha256 = "1qlz0f9w9f2g2qi57mr1djrava3k95ln7qlx27rzx24yyzlhwmc9"; + authors = [ + "Toby Lawrence " + ]; + dependencies = [ + { + name = "portable-atomic"; + packageId = "portable-atomic"; + usesDefaultFeatures = false; + target = { target, features }: ("32" == target."pointer_width" or null); + features = [ "fallback" ]; + } + { + name = "rapidhash"; + packageId = "rapidhash"; + usesDefaultFeatures = false; + } + ]; + + }; + "metrics-exporter-prometheus" = rec { + crateName = "metrics-exporter-prometheus"; + version = "0.18.3"; + edition = "2018"; + sha256 = "024igw9s0ihb93q6h58pdhcb08jqxkm137iis3mwlqlyzkqxic0x"; + libName = "metrics_exporter_prometheus"; + authors = [ + "Toby Lawrence " + ]; + dependencies = [ + { + name = "base64"; + packageId = "base64"; + usesDefaultFeatures = false; + features = [ "std" ]; + } + { + name = "evmap"; + packageId = "evmap"; + } + { + name = "indexmap"; + packageId = "indexmap"; + usesDefaultFeatures = false; + features = [ "std" ]; + } + { + name = "metrics"; + packageId = "metrics"; + } + { + name = "metrics-util"; + packageId = "metrics-util"; + usesDefaultFeatures = false; + features = [ "recency" "registry" "storage" ]; + } + { + name = "quanta"; + packageId = "quanta"; + usesDefaultFeatures = false; + } + { + name = "thiserror"; + packageId = "thiserror 2.0.18"; + usesDefaultFeatures = false; + } + ]; + features = { + "_hyper-client" = [ "http-body-util" "hyper/client" "hyper-util/client" "hyper-util/http1" "hyper-util/client-legacy" "hyper-rustls" ]; + "_hyper-server" = [ "http-body-util" "hyper/server" "hyper-util/server-auto" ]; + "_push-gateway-common" = [ "async-runtime" "rustls" "tracing" "_hyper-client" ]; + "async-runtime" = [ "tokio" "hyper-util/tokio" ]; + "default" = [ "http-listener" "push-gateway" ]; + "http-body-util" = [ "dep:http-body-util" ]; + "http-listener" = [ "async-runtime" "ipnet" "tracing" "_hyper-server" ]; + "hyper" = [ "dep:hyper" ]; + "hyper-rustls" = [ "dep:hyper-rustls" ]; + "hyper-util" = [ "dep:hyper-util" ]; + "ipnet" = [ "dep:ipnet" ]; + "mime" = [ "dep:mime" ]; + "prost" = [ "dep:prost" ]; + "prost-build" = [ "dep:prost-build" ]; + "prost-types" = [ "dep:prost-types" ]; + "protobuf" = [ "mime" "prost" "prost-types" "prost-build" ]; + "push-gateway" = [ "_push-gateway-common" "hyper-rustls/aws-lc-rs" ]; + "push-gateway-no-tls-provider" = [ "_push-gateway-common" ]; + "rustls" = [ "dep:rustls" ]; + "tokio" = [ "dep:tokio" ]; + "tracing" = [ "dep:tracing" ]; + "uds-listener" = [ "http-listener" ]; + }; + }; + "metrics-util" = rec { + crateName = "metrics-util"; + version = "0.20.4"; + edition = "2018"; + sha256 = "04syfklxgh10gih04lixn1p2cch5vwk2z6gdz295yqv2hlpp5y4n"; + libName = "metrics_util"; + authors = [ + "Toby Lawrence " + ]; + dependencies = [ + { + name = "crossbeam-epoch"; + packageId = "crossbeam-epoch"; + optional = true; + usesDefaultFeatures = false; + features = [ "alloc" "std" ]; + } + { + name = "crossbeam-utils"; + packageId = "crossbeam-utils"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "hashbrown"; + packageId = "hashbrown 0.16.1"; + optional = true; + usesDefaultFeatures = false; + features = [ "default-hasher" "raw-entry" ]; + } + { + name = "metrics"; + packageId = "metrics"; + } + { + name = "quanta"; + packageId = "quanta"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "rand"; + packageId = "rand 0.9.4"; + optional = true; + usesDefaultFeatures = false; + features = [ "thread_rng" ]; + } + { + name = "rand_xoshiro"; + packageId = "rand_xoshiro"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "rapidhash"; + packageId = "rapidhash"; + usesDefaultFeatures = false; + } + { + name = "sketches-ddsketch"; + packageId = "sketches-ddsketch 0.3.1"; + optional = true; + usesDefaultFeatures = false; + } + ]; + devDependencies = [ + { + name = "rand"; + packageId = "rand 0.9.4"; + usesDefaultFeatures = false; + features = [ "thread_rng" ]; + } + { + name = "sketches-ddsketch"; + packageId = "sketches-ddsketch 0.3.1"; + usesDefaultFeatures = false; + } + ]; + features = { + "aho-corasick" = [ "dep:aho-corasick" ]; + "crossbeam-epoch" = [ "dep:crossbeam-epoch" ]; + "crossbeam-utils" = [ "dep:crossbeam-utils" ]; + "debugging" = [ "indexmap" "ordered-float" "registry" ]; + "default" = [ "debugging" "layers" "recency" "registry" "storage" ]; + "hashbrown" = [ "dep:hashbrown" ]; + "indexmap" = [ "dep:indexmap" ]; + "layer-filter" = [ "aho-corasick" ]; + "layer-router" = [ "radix_trie" ]; + "layers" = [ "layer-filter" "layer-router" ]; + "ordered-float" = [ "dep:ordered-float" ]; + "quanta" = [ "dep:quanta" ]; + "radix_trie" = [ "dep:radix_trie" ]; + "rand" = [ "dep:rand" ]; + "rand_xoshiro" = [ "dep:rand_xoshiro" ]; + "recency" = [ "registry" "quanta" ]; + "registry" = [ "hashbrown" "storage" ]; + "sketches-ddsketch" = [ "dep:sketches-ddsketch" ]; + "storage" = [ "crossbeam-epoch" "crossbeam-utils" "rand" "rand_xoshiro" "sketches-ddsketch" ]; + }; + resolvedDefaultFeatures = [ "crossbeam-epoch" "crossbeam-utils" "hashbrown" "quanta" "rand" "rand_xoshiro" "recency" "registry" "sketches-ddsketch" "storage" ]; + }; "miette" = rec { crateName = "miette"; version = "7.6.0"; @@ -25416,6 +25699,47 @@ rec { "serde" = [ "dep:serde" ]; }; }; + "rand_xoshiro" = rec { + crateName = "rand_xoshiro"; + version = "0.7.0"; + edition = "2021"; + sha256 = "0h9dv9mn703zb2z5dys7vc4rzy3az8xg99fc5m8zbnh0axkg80zp"; + authors = [ + "The Rand Project Developers" + ]; + dependencies = [ + { + name = "rand_core"; + packageId = "rand_core 0.9.5"; + } + ]; + features = { + "serde" = [ "dep:serde" ]; + }; + }; + "rapidhash" = rec { + crateName = "rapidhash"; + version = "4.5.1"; + edition = "2021"; + crateBin = []; + sha256 = "17jqb1mrdg8vb79ma8gxa21vg21spb47szjvspl5is3c0f5fg9sx"; + authors = [ + "Liam Gray " + ]; + dependencies = [ + { + name = "rustversion"; + packageId = "rustversion"; + } + ]; + features = { + "default" = [ "std" ]; + "getrandom_03" = [ "dep:getrandom_03" ]; + "getrandom_04" = [ "dep:getrandom_04" ]; + "rand" = [ "std" "getrandom_03" ]; + "rng" = [ "dep:rand_core" ]; + }; + }; "raw-cpuid" = rec { crateName = "raw-cpuid"; version = "11.6.0"; @@ -29407,7 +29731,21 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; - "sketches-ddsketch" = rec { + "sketches-ddsketch 0.3.1" = rec { + crateName = "sketches-ddsketch"; + version = "0.3.1"; + edition = "2018"; + sha256 = "0asak4kg6hz7kv4infbmqf3n7srdkgjng8fwqh61wrrdp6p76vqc"; + libName = "sketches_ddsketch"; + authors = [ + "Mike Heffner " + ]; + features = { + "serde" = [ "dep:serde" ]; + "use_serde" = [ "serde" "serde/derive" ]; + }; + }; + "sketches-ddsketch 0.4.0" = rec { crateName = "sketches-ddsketch"; version = "0.4.0"; edition = "2018"; @@ -30476,7 +30814,7 @@ rec { } { name = "sketches-ddsketch"; - packageId = "sketches-ddsketch"; + packageId = "sketches-ddsketch 0.4.0"; features = [ "use_serde" ]; } { -- 2.51.2