Skip to content

Commit 1c0a390

Browse files
committed
feat: non-global metrics collection
1 parent f29c585 commit 1c0a390

File tree

4 files changed

+45
-25
lines changed

4 files changed

+45
-25
lines changed

Cargo.lock

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ unexpected_cfgs = { level = "warn", check-cfg = ["cfg(iroh_docsrs)"] }
3737

3838
[workspace.lints.clippy]
3939
unused-async = "warn"
40+
41+
[patch.crates-io]
42+
iroh-metrics = { git = "https://github.com/n0-computer/iroh-metrics", branch = "Frando/metric-sets" }

portmapper/src/lib.rs

+40-22
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use std::{
88

99
use current_mapping::CurrentMapping;
1010
use futures_lite::StreamExt;
11-
use iroh_metrics::inc;
1211
use netwatch::interfaces::HomeRouter;
1312
use tokio::sync::{mpsc, oneshot, watch};
1413
use tokio_util::task::AbortOnDropHandle;
@@ -141,6 +140,8 @@ pub struct Client {
141140
port_mapping: watch::Receiver<Option<SocketAddrV4>>,
142141
/// Channel used to communicate with the port mapping service.
143142
service_tx: mpsc::Sender<Message>,
143+
/// Metrics collected by the service.
144+
metrics: Metrics,
144145
/// A handle to the service that will cancel the spawned task once the client is dropped.
145146
_service_handle: std::sync::Arc<AbortOnDropHandle<()>>,
146147
}
@@ -154,9 +155,14 @@ impl Default for Client {
154155
impl Client {
155156
/// Create a new port mapping client.
156157
pub fn new(config: Config) -> Self {
158+
Self::with_metrics(config, Default::default())
159+
}
160+
161+
/// Creates a new port mapping client with a previously created metrics collector.
162+
pub fn with_metrics(config: Config, metrics: Metrics) -> Self {
157163
let (service_tx, service_rx) = mpsc::channel(SERVICE_CHANNEL_CAPACITY);
158164

159-
let (service, watcher) = Service::new(config, service_rx);
165+
let (service, watcher) = Service::new(config, service_rx, metrics.clone());
160166

161167
let handle = AbortOnDropHandle::new(tokio::spawn(
162168
async move { service.run().await }.instrument(info_span!("portmapper.service")),
@@ -165,6 +171,7 @@ impl Client {
165171
Client {
166172
port_mapping: watcher,
167173
service_tx,
174+
metrics,
168175
_service_handle: std::sync::Arc::new(handle),
169176
}
170177
}
@@ -232,6 +239,11 @@ impl Client {
232239
pub fn watch_external_address(&self) -> watch::Receiver<Option<SocketAddrV4>> {
233240
self.port_mapping.clone()
234241
}
242+
243+
/// Returns the metrics collected by the service.
244+
pub fn metrics(&self) -> &Metrics {
245+
&self.metrics
246+
}
235247
}
236248

237249
/// Port mapping protocol information obtained during a probe.
@@ -263,6 +275,7 @@ impl Probe {
263275
output: ProbeOutput,
264276
local_ip: Ipv4Addr,
265277
gateway: Ipv4Addr,
278+
metrics: Metrics,
266279
) -> Probe {
267280
let ProbeOutput { upnp, pcp, nat_pmp } = output;
268281
let Config {
@@ -282,8 +295,9 @@ impl Probe {
282295

283296
let mut pcp_probing_task = util::MaybeFuture {
284297
inner: (enable_pcp && !pcp).then(|| {
285-
Box::pin(async {
286-
inc!(Metrics, pcp_probes);
298+
let metrics = metrics.clone();
299+
Box::pin(async move {
300+
metrics.pcp_probes.inc();
287301
pcp::probe_available(local_ip, gateway)
288302
.await
289303
.then(Instant::now)
@@ -302,7 +316,7 @@ impl Probe {
302316
};
303317

304318
if upnp_probing_task.inner.is_some() {
305-
inc!(Metrics, upnp_probes);
319+
metrics.upnp_probes.inc();
306320
}
307321

308322
let mut upnp_done = upnp_probing_task.inner.is_none();
@@ -361,15 +375,15 @@ impl Probe {
361375
}
362376

363377
/// Updates a probe with the `Some` values of another probe that is _assumed_ newer.
364-
fn update(&mut self, probe: Probe) {
378+
fn update(&mut self, probe: Probe, metrics: &Metrics) {
365379
let Probe {
366380
last_probe,
367381
last_upnp_gateway_addr,
368382
last_pcp,
369383
last_nat_pmp,
370384
} = probe;
371385
if last_upnp_gateway_addr.is_some() {
372-
inc!(Metrics, upnp_available);
386+
metrics.upnp_available.inc();
373387
let new_gateway = last_upnp_gateway_addr
374388
.as_ref()
375389
.map(|(addr, _last_seen)| addr);
@@ -378,7 +392,7 @@ impl Probe {
378392
.as_ref()
379393
.map(|(addr, _last_seen)| addr);
380394
if new_gateway != old_gateway {
381-
inc!(Metrics, upnp_gateway_updated);
395+
metrics.upnp_gateway_updated.inc();
382396
debug!(
383397
"upnp gateway changed {:?} -> {:?}",
384398
old_gateway
@@ -392,7 +406,7 @@ impl Probe {
392406
self.last_upnp_gateway_addr = last_upnp_gateway_addr;
393407
}
394408
if last_pcp.is_some() {
395-
inc!(Metrics, pcp_available);
409+
metrics.pcp_available.inc();
396410
self.last_pcp = last_pcp;
397411
}
398412
if last_nat_pmp.is_some() {
@@ -430,12 +444,14 @@ pub struct Service {
430444
/// Requests for a probe that arrive while this task is still in progress will receive the same
431445
/// result.
432446
probing_task: Option<(AbortOnDropHandle<Probe>, Vec<oneshot::Sender<ProbeResult>>)>,
447+
metrics: Metrics,
433448
}
434449

435450
impl Service {
436451
fn new(
437452
config: Config,
438453
rx: mpsc::Receiver<Message>,
454+
metrics: Metrics,
439455
) -> (Self, watch::Receiver<Option<SocketAddrV4>>) {
440456
let (current_mapping, watcher) = CurrentMapping::new();
441457
let mut full_probe = Probe::empty();
@@ -454,6 +470,7 @@ impl Service {
454470
full_probe,
455471
mapping_task: None,
456472
probing_task: None,
473+
metrics,
457474
};
458475

459476
(service, watcher)
@@ -518,7 +535,7 @@ impl Service {
518535
receivers: Vec<oneshot::Sender<ProbeResult>>,
519536
) {
520537
let result = result.map(|probe| {
521-
self.full_probe.update(probe);
538+
self.full_probe.update(probe, &self.metrics);
522539
// TODO(@divma): the gateway of the current mapping could have changed. Tailscale
523540
// still assumes the current mapping is valid/active and will return it even after
524541
// this
@@ -542,11 +559,11 @@ impl Service {
542559
}
543560
Ok(Err(e)) => {
544561
debug!("failed to get a port mapping {e}");
545-
inc!(Metrics, mapping_failures);
562+
self.metrics.mapping_failures.inc();
546563
}
547564
Err(e) => {
548565
debug!("failed to get a port mapping {e}");
549-
inc!(Metrics, mapping_failures);
566+
self.metrics.mapping_failures.inc();
550567
}
551568
}
552569
}
@@ -566,7 +583,7 @@ impl Service {
566583
async fn update_local_port(&mut self, local_port: Option<NonZeroU16>) {
567584
// ignore requests to update the local port in a way that does not produce a change
568585
if local_port != self.local_port {
569-
inc!(Metrics, local_port_updates);
586+
self.metrics.local_port_updates.inc();
570587
let old_port = std::mem::replace(&mut self.local_port, local_port);
571588

572589
// clear the current mapping task if any
@@ -604,7 +621,7 @@ impl Service {
604621

605622
fn get_mapping(&mut self, external_addr: Option<(Ipv4Addr, NonZeroU16)>) {
606623
if let Some(local_port) = self.local_port {
607-
inc!(Metrics, mapping_attempts);
624+
self.metrics.mapping_attempts.inc();
608625

609626
let (local_ip, gateway) = match ip_and_gateway() {
610627
Ok(ip_and_gw) => ip_and_gw,
@@ -683,7 +700,7 @@ impl Service {
683700
// we don't care if the requester is no longer there
684701
let _ = result_tx.send(Ok(probe_output));
685702
} else {
686-
inc!(Metrics, probes_started);
703+
self.metrics.probes_started.inc();
687704

688705
let (local_ip, gateway) = match ip_and_gateway() {
689706
Ok(ip_and_gw) => ip_and_gw,
@@ -696,13 +713,14 @@ impl Service {
696713
};
697714

698715
let config = self.config.clone();
699-
let handle =
700-
tokio::spawn(
701-
async move {
702-
Probe::from_output(config, probe_output, local_ip, gateway).await
703-
}
704-
.instrument(info_span!("portmapper.probe")),
705-
);
716+
let metrics = self.metrics.clone();
717+
let handle = tokio::spawn(
718+
async move {
719+
Probe::from_output(config, probe_output, local_ip, gateway, metrics)
720+
.await
721+
}
722+
.instrument(info_span!("portmapper.probe")),
723+
);
706724
let receivers = vec![result_tx];
707725
self.probing_task = Some((AbortOnDropHandle::new(handle), receivers));
708726
}

portmapper/src/metrics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl Default for Metrics {
6262
}
6363

6464
impl Metric for Metrics {
65-
fn name() -> &'static str {
65+
fn name(&self) -> &'static str {
6666
"portmap"
6767
}
6868
}

0 commit comments

Comments
 (0)