diff --git a/Cargo.lock b/Cargo.lock index b36f68df..52e13ec8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -785,6 +785,7 @@ dependencies = [ "http", "http-serde", "lorawan", + "metrics", "prost", "rand", "semtech-udp", @@ -792,7 +793,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sha2 0.9.9", + "sha2 0.10.6", "signature 2.0.0", "thiserror", "tokio", @@ -1214,6 +1215,28 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "metrics" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b9b8653cec6897f73b519a43fba5ee3d50f62fe9af80b428accdcc093b4a849" +dependencies = [ + "ahash 0.7.6", + "metrics-macros", + "portable-atomic", +] + +[[package]] +name = "metrics-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731f8ecebd9f3a4aa847dfe75455e4757a45da40a7793d2f0b1f9b6ed18b23f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "mime" version = "0.3.16" @@ -1395,6 +1418,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" + [[package]] name = "ppv-lite86" version = "0.2.17" diff --git a/Cargo.toml b/Cargo.toml index 5a9bc4e5..5929646a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ beacon = { package = "beacon", path = "beacon" } exponential-backoff = {git = "https://github.com/yoshuawuyts/exponential-backoff", branch = "master"} semtech-udp = { version = ">=0.10.7", default-features=false, features=["server"] } helium-crypto = "0.6" +metrics = {version = "0", default-features = false} [features] default = [ "ecc608" ] diff --git a/src/gateway.rs b/src/gateway.rs index 962dfc0d..f430f5e0 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -1,6 +1,11 @@ use crate::{ - beaconer, packet, packet_router, region_watcher, sync, PacketDown, PacketUp, RegionParams, - Result, Settings, + beaconer, + metrics::{ + BEACON_FAILED, BEACON_TRANSMITTED, BEACON_TRANSMITTED_ADJUSTED, DOWNLINK_FAILED, + DOWNLINK_TRANSMITTED, DOWNLINK_TRANSMITTED_ADJUSTED, + }, + packet, packet_router, region_watcher, sync, PacketDown, PacketUp, RegionParams, Result, + Settings, }; use beacon::Beacon; use lorawan::PHYPayload; @@ -181,6 +186,7 @@ impl Gateway { Ok(tx_power) => tx_power, Err(err) => { warn!(%err, "beacon transmit"); + metrics::increment_counter!(BEACON_FAILED); responder.send(Err(err)); return; } @@ -190,6 +196,7 @@ impl Gateway { Ok(packet) => packet, Err(err) => { warn!(%err, "failed to construct beacon pull resp"); + metrics::increment_counter!(BEACON_FAILED); responder.send(Err(err)); return; } @@ -207,6 +214,7 @@ impl Gateway { ?tmst, "beacon transmitted" ); + metrics::increment_counter!(BEACON_TRANSMITTED); responder.send(Ok(BeaconResp { powe: tx_power as i32, tmst: tmst.unwrap_or(0), @@ -221,6 +229,7 @@ impl Gateway { match power_used { None => { warn!("packet transmitted with adjusted power, but packet forwarder does not indicate power used."); + metrics::increment_counter!(BEACON_TRANSMITTED_ADJUSTED); responder.send(Err(GatewayError::NoBeaconTxPower.into())); } Some(actual_power) => { @@ -230,6 +239,7 @@ impl Gateway { ?tmst, "beacon transmitted with adjusted power output", ); + metrics::increment_counter!(BEACON_TRANSMITTED_ADJUSTED); responder.send(Ok(BeaconResp { powe: actual_power, tmst: tmst.unwrap_or(0), @@ -239,6 +249,7 @@ impl Gateway { tmst } else { warn!(beacon_id, %err, "failed to transmit beacon"); + metrics::increment_counter!(BEACON_FAILED); responder.send(Err(GatewayError::BeaconTxFailure.into())); None } @@ -252,6 +263,7 @@ impl Gateway { Ok(tx_power) => tx_power, Err(err) => { warn!(%err, "downlink transmit"); + metrics::increment_counter!(DOWNLINK_FAILED); return; } }; @@ -280,19 +292,27 @@ impl Gateway { match downlink_rx2.dispatch(Some(DOWNLINK_TIMEOUT)).await { Err(SemtechError::Ack(TxAckErr::AdjustedTransmitPower(_, _))) => { warn!("rx2 downlink sent with adjusted transmit power"); + metrics::increment_counter!(DOWNLINK_TRANSMITTED_ADJUSTED, "window" => "rx2") + } + Err(err) => { + warn!(%err, "ignoring rx2 downlink error"); + metrics::increment_counter!(DOWNLINK_FAILED, "window" => "rx2"); + } + Ok(_) => { + metrics::increment_counter!(DOWNLINK_TRANSMITTED, "window" => "rx2") } - Err(err) => warn!(%err, "ignoring rx2 downlink error"), - _ => (), } } } Err(SemtechError::Ack(TxAckErr::AdjustedTransmitPower(_, _))) => { warn!("rx1 downlink sent with adjusted transmit power"); + metrics::increment_counter!(DOWNLINK_TRANSMITTED_ADJUSTED, "window" => "rx1") } Err(err) => { warn!(%err, "ignoring rx1 downlink error"); + metrics::increment_counter!(DOWNLINK_FAILED, "window" => "rx1"); } - Ok(_) => (), + Ok(_) => metrics::increment_counter!(DOWNLINK_TRANSMITTED, "window" => "rx1"), } } }); diff --git a/src/lib.rs b/src/lib.rs index 10e4e860..2af5ffe7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod keypair; pub mod message_cache; pub mod packet; +pub mod metrics; pub mod packet_router; pub mod region_watcher; pub mod server; diff --git a/src/metrics.rs b/src/metrics.rs new file mode 100644 index 00000000..db4d1a58 --- /dev/null +++ b/src/metrics.rs @@ -0,0 +1,12 @@ +pub const UPLINK_QUEUED: &str = "uplink_queued"; +pub const UPLINK_DELIVERED: &str = "uplink_delivered"; +pub const UPLINK_FAILED: &str = "uplink_failed"; +pub const UPLINK_DISCARDED: &str = "uplink_discarded"; + +pub const DOWNLINK_TRANSMITTED: &str = "downlink_transmitted"; +pub const DOWNLINK_TRANSMITTED_ADJUSTED: &str = "downlink_transmitted_adjusted"; +pub const DOWNLINK_FAILED: &str = "downlink_failed"; + +pub const BEACON_TRANSMITTED: &str = "beacon_transmitted"; +pub const BEACON_TRANSMITTED_ADJUSTED: &str = "beacon_transmitted_adjusted"; +pub const BEACON_FAILED: &str = "beacon_failed"; diff --git a/src/packet_router/mod.rs b/src/packet_router/mod.rs index dd3612af..7cc4863d 100644 --- a/src/packet_router/mod.rs +++ b/src/packet_router/mod.rs @@ -1,6 +1,7 @@ use crate::{ gateway, message_cache::{CacheMessage, MessageCache}, + metrics::{UPLINK_DELIVERED, UPLINK_DISCARDED, UPLINK_FAILED, UPLINK_QUEUED}, region_watcher, service::packet_router::PacketRouterService, sync, Base64, Keypair, MsgSign, PacketUp, RegionParams, Result, Settings, @@ -159,6 +160,7 @@ impl PacketRouter { async fn handle_uplink(&mut self, uplink: PacketUp, received: StdInstant) { self.store.push_back(uplink, received); + metrics::increment_counter!(UPLINK_QUEUED); self.send_waiting_packets().await; } @@ -170,9 +172,14 @@ impl PacketRouter { while let (removed, Some(packet)) = self.store.pop_front(STORE_GC_INTERVAL) { if removed > 0 { info!("discarded {removed} queued packets"); + metrics::counter!(UPLINK_DISCARDED, removed as u64); } - if let Err(err) = self.send_packet(packet).await { - warn!(%err, "failed to send uplink") + match self.send_packet(packet).await { + Ok(_) => metrics::increment_counter!(UPLINK_DELIVERED), + Err(err) => { + warn!(%err, "failed to send uplink"); + metrics::increment_counter!(UPLINK_FAILED); + } } } }