diff --git a/Cargo.lock b/Cargo.lock index 06ff9e5780..95685f31c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -557,9 +557,9 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "itoa", "matchit", "memchr", @@ -587,8 +587,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "mime", "rustversion", "tower-layer", @@ -3011,7 +3011,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http", + "http 0.2.9", "js-sys", "pin-project", "serde", @@ -3080,7 +3080,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -3290,6 +3290,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-api-client" version = "0.1.0" @@ -3311,7 +3322,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", + "pin-project-lite 0.2.13", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite 0.2.13", ] @@ -3379,8 +3413,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -3392,6 +3426,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite 0.2.13", + "smallvec", + "tokio", +] + [[package]] name = "hyper-rustls" version = "0.24.1" @@ -3399,8 +3452,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "rustls 0.21.10", "tokio", "tokio-rustls 0.24.1", @@ -3412,12 +3465,28 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.27", "pin-project-lite 0.2.13", "tokio", "tokio-io-timeout", ] +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.2.0", + "pin-project-lite 0.2.13", + "socket2 0.5.4", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3742,7 +3811,7 @@ dependencies = [ "curl-sys", "event-listener", "futures-lite", - "http", + "http 0.2.9", "log", "once_cell", "polling", @@ -4555,7 +4624,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.9", "httparse", "log", "memchr", @@ -5192,7 +5261,10 @@ dependencies = [ "dirs 4.0.0", "futures", "gloo-timers", + "http-body-util", "humantime-serde", + "hyper 1.2.0", + "hyper-util", "log", "nym-bandwidth-controller", "nym-config", @@ -5201,6 +5273,7 @@ dependencies = [ "nym-explorer-client", "nym-gateway-client", "nym-gateway-requests", + "nym-metrics", "nym-network-defaults", "nym-nonexhaustive-delayqueue", "nym-pemstore", @@ -5514,7 +5587,7 @@ dependencies = [ "dotenvy", "futures", "humantime-serde", - "hyper", + "hyper 0.14.27", "ipnetwork 0.16.0", "log", "nym-api-requests", @@ -5719,7 +5792,6 @@ dependencies = [ "lazy_static", "log", "prometheus", - "regex", ] [[package]] @@ -5950,7 +6022,7 @@ dependencies = [ "dashmap", "fastrand 2.0.1", "hmac 0.12.1", - "hyper", + "hyper 0.14.27", "ipnetwork 0.16.0", "mime", "nym-config", @@ -6103,7 +6175,7 @@ dependencies = [ "dotenvy", "futures", "hex", - "http", + "http 0.2.9", "httpcodec", "libp2p", "log", @@ -6843,7 +6915,7 @@ checksum = "a819b71d6530c4297b49b3cae2939ab3a8cc1b9f382826a1bc29dd0ca3864906" dependencies = [ "async-trait", "bytes", - "http", + "http 0.2.9", "isahc", "opentelemetry_api", ] @@ -6857,7 +6929,7 @@ dependencies = [ "async-trait", "futures", "futures-executor", - "http", + "http 0.2.9", "isahc", "once_cell", "opentelemetry", @@ -8038,9 +8110,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-rustls", "ipnet", "js-sys", @@ -8199,7 +8271,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfac3a1df83f8d4fc96aa41dba3b86c786417b7fc0f52ec76295df2ba781aa69" dependencies = [ - "http", + "http 0.2.9", "log", "regex", "rocket", @@ -8219,8 +8291,8 @@ dependencies = [ "cookie", "either", "futures", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "indexmap 2.0.2", "log", "memchr", @@ -9024,9 +9096,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "snafu" @@ -9978,9 +10050,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-timeout", "percent-encoding", "pin-project", @@ -10023,8 +10095,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "http-range-header", "httpdate", "mime", @@ -10302,7 +10374,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", "rand 0.8.5", diff --git a/common/client-core/Cargo.toml b/common/client-core/Cargo.toml index dc6c9bba2b..fdc6a39b7a 100644 --- a/common/client-core/Cargo.toml +++ b/common/client-core/Cargo.toml @@ -27,7 +27,7 @@ tap = "1.0.1" thiserror = { workspace = true } url = { workspace = true, features = ["serde"] } tungstenite = { workspace = true, default-features = false } -tokio = { workspace = true, features = ["macros"]} +tokio = { workspace = true, features = ["macros"] } time = "0.3.17" zeroize = { workspace = true } @@ -38,6 +38,7 @@ nym-crypto = { path = "../crypto" } nym-explorer-client = { path = "../../explorer-api/explorer-client" } nym-gateway-client = { path = "../client-libs/gateway-client" } nym-gateway-requests = { path = "../../gateway/gateway-requests" } +nym-metrics = { path = "../nym-metrics" } nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" } nym-sphinx = { path = "../nymsphinx" } nym-pemstore = { path = "../pemstore" } @@ -48,6 +49,19 @@ nym-credential-storage = { path = "../credential-storage" } nym-network-defaults = { path = "../network-defaults" } si-scale = "0.2.2" +### For serving prometheus metrics +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper] +version = "1" +features = ["server", "http1"] + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.http-body-util] +version = "0.1" + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper-util] +version = "0.1" +features = ["tokio"] +### + [target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream] version = "0.1.11" features = ["time"] @@ -91,11 +105,15 @@ tempfile = "3.1.0" [build-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } -sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } +sqlx = { workspace = true, features = [ + "runtime-tokio-rustls", + "sqlite", + "macros", + "migrate", +] } [features] default = [] cli = ["clap"] fs-surb-storage = ["sqlx"] wasm = ["nym-gateway-client/wasm"] - diff --git a/common/client-core/src/client/packet_statistics_control.rs b/common/client-core/src/client/packet_statistics_control.rs index a50e0c596c..8f5aaf434d 100644 --- a/common/client-core/src/client/packet_statistics_control.rs +++ b/common/client-core/src/client/packet_statistics_control.rs @@ -3,8 +3,30 @@ use std::{ time::{Duration, Instant}, }; +use log::{info, warn}; +use nym_metrics::{inc, inc_by, metrics}; use si_scale::helpers::bibytes2; +// Metrics server +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use http_body_util::Full; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use hyper::body::Bytes; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use hyper::server::conn::http1; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use hyper::service::service_fn; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use hyper::{Request, Response}; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use hyper_util::rt::TokioIo; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use std::convert::Infallible; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use std::net::SocketAddr; +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] +use tokio::net::TcpListener; + use crate::spawn_future; // Time interval between reporting packet statistics @@ -53,42 +75,60 @@ impl PacketStatistics { PacketStatisticsEvent::RealPacketSent(packet_size) => { self.real_packets_sent += 1; self.real_packets_sent_size += packet_size; + inc!("real_packets_sent"); + inc_by!("real_packets_sent_size", packet_size); } PacketStatisticsEvent::CoverPacketSent(packet_size) => { self.cover_packets_sent += 1; self.cover_packets_sent_size += packet_size; + inc!("cover_packets_sent"); + inc_by!("cover_packets_sent_size", packet_size); } PacketStatisticsEvent::RealPacketReceived(packet_size) => { self.real_packets_received += 1; self.real_packets_received_size += packet_size; + inc!("real_packets_received"); + inc_by!("real_packets_received_size", packet_size); } PacketStatisticsEvent::CoverPacketReceived(packet_size) => { self.cover_packets_received += 1; self.cover_packets_received_size += packet_size; + inc!("cover_packets_received"); + inc_by!("cover_packets_received_size", packet_size); } PacketStatisticsEvent::AckReceived(packet_size) => { self.total_acks_received += 1; self.total_acks_received_size += packet_size; + inc!("total_acks_received"); + inc_by!("total_acks_received_size", packet_size); } PacketStatisticsEvent::RealAckReceived(packet_size) => { self.real_acks_received += 1; self.real_acks_received_size += packet_size; + inc!("real_acks_received"); + inc_by!("real_acks_received_size", packet_size); } PacketStatisticsEvent::CoverAckReceived(packet_size) => { self.cover_acks_received += 1; self.cover_acks_received_size += packet_size; + inc!("cover_acks_received"); + inc_by!("cover_acks_received_size", packet_size); } PacketStatisticsEvent::RealPacketQueued => { self.real_packets_queued += 1; + inc!("real_packets_queued"); } PacketStatisticsEvent::RetransmissionQueued => { self.retransmissions_queued += 1; + inc!("retransmissions_queued"); } PacketStatisticsEvent::ReplySurbRequestQueued => { self.reply_surbs_queued += 1; + inc!("reply_surbs_queued"); } PacketStatisticsEvent::AdditionalReplySurbRequestQueued => { self.additional_reply_surbs_queued += 1; + inc!("additional_reply_surbs_queued"); } } } @@ -465,6 +505,33 @@ impl PacketStatisticsControl { let snapshot_interval = Duration::from_millis(SNAPSHOT_INTERVAL_MS); let mut snapshot_interval = tokio::time::interval(snapshot_interval); + cfg_if::cfg_if! { + if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { + log::warn!("Metrics server is not supported on wasm32-unknown-unknown"); + let listener = None; + } else { + let mut metrics_port = 18000; + let listener: Option; + loop { + let addr = SocketAddr::from(([0, 0, 0, 0], metrics_port)); + match TcpListener::bind(addr).await { + Ok(l) => { + info!("###############################"); + info!("Metrics endpoint is at: {:?}", l.local_addr()); + info!("###############################"); + listener = Some(l); + break; + }, + Err(err) => { + log::warn!("Failed to bind metrics server: {:?}", err); + metrics_port += 1; + } + }; + } + + } + } + loop { tokio::select! { stats_event = self.stats_rx.recv() => match stats_event { @@ -477,6 +544,27 @@ impl PacketStatisticsControl { break; } }, + // conditional will disable the branch if we're in wasm32-unknown-unknown + result = listener.as_ref().unwrap().accept(), if listener.is_some() => { + cfg_if::cfg_if! { + if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] { + if let Ok((stream, _)) = result { + let io = TokioIo::new(stream); + + tokio::task::spawn(async move { + if let Err(err) = http1::Builder::new() + .serve_connection(io, service_fn(serve_metrics)) + .await + { + warn!("Error serving connection: {:?}", err); + } + }); + } else { + warn!("Error accepting connection"); + } + } + } + } _ = snapshot_interval.tick() => { self.update_history(); self.update_rates(); @@ -501,3 +589,9 @@ impl PacketStatisticsControl { }) } } + +async fn serve_metrics( + _: Request, +) -> Result>, Infallible> { + Ok(Response::new(Full::new(Bytes::from(metrics!())))) +} diff --git a/common/nym-metrics/Cargo.toml b/common/nym-metrics/Cargo.toml index 0b49297719..537a69a142 100644 --- a/common/nym-metrics/Cargo.toml +++ b/common/nym-metrics/Cargo.toml @@ -14,5 +14,4 @@ license.workspace = true prometheus = { workspace = true } log = { workspace = true } dashmap = { workspace = true } -regex = "1.1" lazy_static = "1.4" diff --git a/common/nym-metrics/src/lib.rs b/common/nym-metrics/src/lib.rs index d67aae7b94..a9e22909d3 100644 --- a/common/nym-metrics/src/lib.rs +++ b/common/nym-metrics/src/lib.rs @@ -1,12 +1,47 @@ use dashmap::DashMap; pub use log::error; use log::{debug, warn}; -use regex::Regex; use std::fmt; pub use std::time::Instant; use prometheus::{core::Collector, Counter, Encoder as _, Gauge, Registry, TextEncoder}; +#[macro_export] +macro_rules! prepend_package_name { + ($name: literal) => { + &format!( + "{}_{}", + std::module_path!() + .split("::") + .next() + .unwrap_or("x") + .to_string(), + $name + ) + }; +} + +#[macro_export] +macro_rules! inc_by { + ($name:literal, $x:expr) => { + $crate::REGISTRY.inc_by($crate::prepend_package_name!($name), $x as f64); + }; +} + +#[macro_export] +macro_rules! inc { + ($name:literal) => { + $crate::REGISTRY.inc($crate::prepend_package_name!($name)); + }; +} + +#[macro_export] +macro_rules! metrics { + () => { + $crate::REGISTRY.to_string(); + }; +} + #[macro_export] macro_rules! nanos { ( $name:literal, $x:expr ) => {{ @@ -14,13 +49,13 @@ macro_rules! nanos { // if the block needs to return something, we can return it let r = $x; let duration = start.elapsed().as_nanos() as f64; + let name = $crate::prepend_package_name!($name); $crate::REGISTRY.inc_by(&format!("{}_nanos", $name), duration); r }}; } lazy_static::lazy_static! { - pub static ref RE: Regex = Regex::new(r"[^a-zA-Z0-9_]").unwrap(); pub static ref REGISTRY: MetricsController = MetricsController::default(); } @@ -43,6 +78,7 @@ fn fq_name(c: &dyn Collector) -> String { } impl Metric { + #[inline(always)] fn fq_name(&self) -> String { match self { Metric::C(c) => fq_name(c.as_ref()), @@ -50,6 +86,15 @@ impl Metric { } } + #[inline(always)] + fn inc(&self) { + match self { + Metric::C(c) => c.inc(), + Metric::G(g) => g.inc(), + } + } + + #[inline(always)] fn inc_by(&self, value: f64) { match self { Metric::C(c) => c.inc_by(value), @@ -57,6 +102,7 @@ impl Metric { } } + #[inline(always)] fn set(&self, value: f64) { match self { Metric::C(_c) => { @@ -69,14 +115,8 @@ impl Metric { impl fmt::Display for MetricsController { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut buffer = vec![]; - let encoder = TextEncoder::new(); - let metrics = self.registry.gather(); - match encoder.encode(&metrics, &mut buffer) { - Ok(_) => {} - Err(e) => return write!(f, "Error encoding metrics to buffer: {}", e), - } - let output = match String::from_utf8(buffer) { + let metrics = self.gather(); + let output = match String::from_utf8(metrics) { Ok(output) => output, Err(e) => return write!(f, "Error decoding metrics to String: {}", e), }; @@ -85,6 +125,26 @@ impl fmt::Display for MetricsController { } impl MetricsController { + #[inline(always)] + pub fn gather(&self) -> Vec { + let mut buffer = vec![]; + let encoder = TextEncoder::new(); + let metrics = self.registry.gather(); + match encoder.encode(&metrics, &mut buffer) { + Ok(_) => {} + Err(e) => error!("Error encoding metrics to buffer: {}", e), + } + buffer + } + + pub fn to_writer(&self, writer: &mut dyn std::io::Write) { + let metrics = self.gather(); + match writer.write_all(&metrics) { + Ok(_) => {} + Err(e) => error!("Error writing metrics to writer: {}", e), + } + } + pub fn set(&self, name: &str, value: f64) { if let Some(metric) = self.registry_index.get(name) { metric.set(value); @@ -101,6 +161,22 @@ impl MetricsController { } } + pub fn inc(&self, name: &str) { + if let Some(metric) = self.registry_index.get(name) { + metric.inc(); + } else { + let counter = match Counter::new(sanitize_metric_name(name), name) { + Ok(c) => c, + Err(e) => { + debug!("Failed to create counter {:?}:\n{}", name, e); + return; + } + }; + self.register_counter(Box::new(counter)); + self.inc(name) + } + } + pub fn inc_by(&self, name: &str, value: f64) { if let Some(metric) = self.registry_index.get(name) { metric.inc_by(value); @@ -161,9 +237,31 @@ impl MetricsController { } } -#[inline(always)] fn sanitize_metric_name(name: &str) -> String { - RE.replace_all(name, "_").to_string() + // The first character must be [a-zA-Z_:], and all subsequent characters must be [a-zA-Z0-9_:]. + let mut out = String::with_capacity(name.len()); + let mut is_invalid: fn(char) -> bool = invalid_metric_name_start_character; + for c in name.chars() { + if is_invalid(c) { + out.push('_'); + } else { + out.push(c); + } + is_invalid = invalid_metric_name_character; + } + out +} + +#[inline] +fn invalid_metric_name_start_character(c: char) -> bool { + // Essentially, needs to match the regex pattern of [a-zA-Z_:]. + !(c.is_ascii_alphabetic() || c == '_' || c == ':') +} + +#[inline] +fn invalid_metric_name_character(c: char) -> bool { + // Essentially, needs to match the regex pattern of [a-zA-Z0-9_:]. + !(c.is_ascii_alphanumeric() || c == '_' || c == ':') } #[cfg(test)] @@ -174,7 +272,7 @@ mod tests { fn test_sanitization() { assert_eq!( sanitize_metric_name("packets_sent_34.242.65.133:1789"), - "packets_sent_34_242_65_133_1789" + "packets_sent_34_242_65_133:1789" ) } } diff --git a/mixnode/src/node/http/legacy/stats.rs b/mixnode/src/node/http/legacy/stats.rs index 1bbc6eea21..c986acee2b 100644 --- a/mixnode/src/node/http/legacy/stats.rs +++ b/mixnode/src/node/http/legacy/stats.rs @@ -7,7 +7,7 @@ use axum::{ extract::{Query, State}, http::HeaderMap, }; -use nym_metrics::REGISTRY; +use nym_metrics::metrics; use nym_node::http::api::{FormattedResponse, Output}; use serde::{Deserialize, Serialize}; @@ -24,7 +24,7 @@ pub(crate) async fn metrics(State(state): State, headers: Heade if let Some(metrics_key) = state.metrics_key { if let Some(auth) = headers.get("Authorization") { if auth.to_str().unwrap_or_default() == format!("Bearer {}", metrics_key) { - REGISTRY.to_string() + metrics!() } else { "Unauthorized".to_string() } @@ -50,7 +50,7 @@ pub(crate) async fn stats( async fn generate_stats(full: bool, stats: SharedNodeStats) -> NodeStatsResponse { let snapshot_data = stats.clone_data().await; if full { - NodeStatsResponse::Full(REGISTRY.to_string()) + NodeStatsResponse::Full(metrics!()) } else { NodeStatsResponse::Simple(snapshot_data.simplify()) } diff --git a/mixnode/src/node/node_statistics.rs b/mixnode/src/node/node_statistics.rs index 935ce6f3df..aaabbb7a30 100644 --- a/mixnode/src/node/node_statistics.rs +++ b/mixnode/src/node/node_statistics.rs @@ -1,7 +1,7 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use nym_metrics::REGISTRY; +use nym_metrics::inc_by; use super::TaskClient; use futures::channel::mpsc; @@ -65,11 +65,14 @@ impl SharedNodeStats { guard.packets_dropped_since_startup_all += count; } - REGISTRY.inc_by("packets_received_since_startup", new_received); - REGISTRY.inc_by("packets_sent_since_startup_all", new_sent.values().sum()); - REGISTRY.inc_by( + inc_by!("packets_received_since_startup", new_received); + inc_by!( + "packets_sent_since_startup_all", + new_sent.values().sum::() + ); + inc_by!( "packets_dropped_since_startup_all", - new_dropped.values().sum(), + new_dropped.values().sum::() ); guard.packets_received_since_last_update = new_received; @@ -509,6 +512,7 @@ impl Controller { #[cfg(test)] mod tests { use super::*; + use nym_metrics::metrics; use nym_task::TaskManager; #[tokio::test] @@ -538,6 +542,6 @@ mod tests { assert_eq!(&stats.packets_sent_since_last_update.len(), &1); assert_eq!(&stats.packets_received_since_startup, &0.); assert_eq!(&stats.packets_dropped_since_startup_all, &0.); - assert_eq!(REGISTRY.to_string(), "# HELP packets_dropped_since_startup_all packets_dropped_since_startup_all\n# TYPE packets_dropped_since_startup_all counter\npackets_dropped_since_startup_all 0\n# HELP packets_received_since_startup packets_received_since_startup\n# TYPE packets_received_since_startup counter\npackets_received_since_startup 0\n# HELP packets_sent_since_startup_all packets_sent_since_startup_all\n# TYPE packets_sent_since_startup_all counter\npackets_sent_since_startup_all 2\n") + assert_eq!(metrics!(), "# HELP nym_mixnode_packets_dropped_since_startup_all nym_mixnode_packets_dropped_since_startup_all\n# TYPE nym_mixnode_packets_dropped_since_startup_all counter\nnym_mixnode_packets_dropped_since_startup_all 0\n# HELP nym_mixnode_packets_received_since_startup nym_mixnode_packets_received_since_startup\n# TYPE nym_mixnode_packets_received_since_startup counter\nnym_mixnode_packets_received_since_startup 0\n# HELP nym_mixnode_packets_sent_since_startup_all nym_mixnode_packets_sent_since_startup_all\n# TYPE nym_mixnode_packets_sent_since_startup_all counter\nnym_mixnode_packets_sent_since_startup_all 2\n") } } diff --git a/scripts/prom_targets.py b/scripts/prom_targets.py index e7887e1ed1..44ea2a3c83 100644 --- a/scripts/prom_targets.py +++ b/scripts/prom_targets.py @@ -72,7 +72,9 @@ def config_to_targets(config, mixnodes, labels=None): def make_prom_target(env, mixnode, port=None, labels=None): bond_info = mixnode.get("bond_information", {}) - mix_node = bond_info.get("mix_node", {}) + mix_node = bond_info.get("mix_node") + if mix_node is None: + mix_node = mixnode.get("gateway") host = mix_node.get("host", None) port = port if port else mix_node.get("http_api_port", None) if host is None or port is None: diff --git a/scripts/static_prom_targets.py b/scripts/static_prom_targets.py new file mode 100644 index 0000000000..e3490ea089 --- /dev/null +++ b/scripts/static_prom_targets.py @@ -0,0 +1,43 @@ +import json +import os + + +ips = [ + "2.221.182.179", + "54.232.20.104", + "15.237.112.155", + "54.93.108.209", + "13.38.74.100", + "15.237.93.154", + "18.156.175.57", + "3.76.123.170", +] + +port_range = range(18000, 18999) + + +def make_prom_target(ip, port, env): + return { + "targets": [f"{ip}:{port}"], + "labels": { + "mixnet_env": env, + }, + } + + +if __name__ == "__main__": + outfile = "/tmp/tmp_static_prom_tragets.json" + outlink = "/tmp/static_prom_tragets.json" + targets = [] + for ip in ips: + for port in port_range: + targets.append(make_prom_target(ip, port, "performance")) + + with open(outfile, "w") as f: + json.dump(targets, f) + + os.chmod(outfile, 0o777) + os.rename(outfile, outlink) + os.chmod(outlink, 0o777) + + print(f"Prometheus -> {len(targets)} targets written to {outlink}")