Skip to content

Commit 441c242

Browse files
authored
feat(libp2p): track bandwidth per transport protocol stack
Previously one could use the `with_bandwidth_logging` to measure the overall bandwidth usage, only differentiated by inbound and outbound traffic. With this commit bandwidth can be tracked per transport protocol stack (e.g. `/ip4/tcp`) exposed as Prometheus metrics through `libp2p_metrics::BandwidthMetricTransport`. ``` # HELP libp2p_bandwidth_bytes Bandwidth usage by direction and transport protocols. # TYPE libp2p_bandwidth_bytes counter # UNIT libp2p_bandwidth_bytes bytes libp2p_bandwidth_bytes_total{protocols="/ip4/tcp",direction="Outbound"} 1352 libp2p_bandwidth_bytes_total{protocols="/ip4/tcp",direction="Inbound"} 1484 ``` Pull-Request: #4727.
1 parent 9ab0e6f commit 441c242

File tree

20 files changed

+529
-41
lines changed

20 files changed

+529
-41
lines changed

Cargo.lock

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ libp2p-identity = { version = "0.2.7" }
8585
libp2p-kad = { version = "0.45.1", path = "protocols/kad" }
8686
libp2p-mdns = { version = "0.45.0", path = "protocols/mdns" }
8787
libp2p-memory-connection-limits = { version = "0.2.0", path = "misc/memory-connection-limits" }
88-
libp2p-metrics = { version = "0.14.0", path = "misc/metrics" }
88+
libp2p-metrics = { version = "0.14.1", path = "misc/metrics" }
8989
libp2p-mplex = { version = "0.41.0", path = "muxers/mplex" }
9090
libp2p-muxer-test-harness = { path = "muxers/test-harness" }
9191
libp2p-noise = { version = "0.44.0", path = "transports/noise" }
@@ -97,7 +97,7 @@ libp2p-quic = { version = "0.10.0", path = "transports/quic" }
9797
libp2p-relay = { version = "0.17.0", path = "protocols/relay" }
9898
libp2p-rendezvous = { version = "0.14.0", path = "protocols/rendezvous" }
9999
libp2p-request-response = { version = "0.26.0", path = "protocols/request-response" }
100-
libp2p-server = { version = "0.12.3", path = "misc/server" }
100+
libp2p-server = { version = "0.12.4", path = "misc/server" }
101101
libp2p-swarm = { version = "0.44.0", path = "swarm" }
102102
libp2p-swarm-derive = { version = "=0.34.0", path = "swarm-derive" } # `libp2p-swarm-derive` may not be compatible with different `libp2p-swarm` non-breaking releases. E.g. `libp2p-swarm` might introduce a new enum variant `FromSwarm` (which is `#[non-exhaustive]`) in a non-breaking release. Older versions of `libp2p-swarm-derive` would not forward this enum variant within the `NetworkBehaviour` hierarchy. Thus the version pinning is required.
103103
libp2p-swarm-test = { version = "0.3.0", path = "swarm-test" }

examples/metrics/src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,16 @@ mod http_service;
4040
async fn main() -> Result<(), Box<dyn Error>> {
4141
setup_tracing()?;
4242

43+
let mut metric_registry = Registry::default();
44+
4345
let mut swarm = libp2p::SwarmBuilder::with_new_identity()
4446
.with_tokio()
4547
.with_tcp(
4648
tcp::Config::default(),
4749
noise::Config::new,
4850
yamux::Config::default,
4951
)?
52+
.with_bandwidth_metrics(&mut metric_registry)
5053
.with_behaviour(|key| Behaviour::new(key.public()))?
5154
.with_swarm_config(|cfg| cfg.with_idle_connection_timeout(Duration::from_secs(u64::MAX)))
5255
.build();
@@ -59,7 +62,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
5962
tracing::info!(address=%addr, "Dialed address")
6063
}
6164

62-
let mut metric_registry = Registry::default();
6365
let metrics = Metrics::new(&mut metric_registry);
6466
tokio::spawn(http_service::metrics_server(metric_registry));
6567

libp2p/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
- Remove deprecated `development_transport`.
1919
Use `libp2p::SwarmBuilder` instead.
2020
See [PR 4732](https://github.com/libp2p/rust-libp2p/pull/4732).
21+
- Introduce `SwarmBuilder::with_bandwidth_metrics` exposing Prometheus bandwidth metrics per transport protocol stack and direction (in-/ outbound).
22+
Deprecate `Transport::with_bandwidth_logging` and `SwarmBuilder::with_bandwidth_logging` in favor of the new `SwarmBuilder::with_bandwidth_metrics`.
23+
See [PR 4727](https://github.com/libp2p/rust-libp2p/pull/4727).
2124

2225
## 0.52.4
2326

libp2p/src/bandwidth.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919
// DEALINGS IN THE SOFTWARE.
2020

21+
#![allow(deprecated)]
22+
2123
use crate::core::muxing::{StreamMuxer, StreamMuxerEvent};
2224

2325
use futures::{
@@ -101,6 +103,9 @@ where
101103
}
102104

103105
/// Allows obtaining the average bandwidth of the streams.
106+
#[deprecated(
107+
note = "Use `libp2p::SwarmBuilder::with_bandwidth_metrics` or `libp2p_metrics::BandwidthTransport` instead."
108+
)]
104109
pub struct BandwidthSinks {
105110
inbound: AtomicU64,
106111
outbound: AtomicU64,

libp2p/src/builder.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ mod tests {
7373
use crate::SwarmBuilder;
7474
use libp2p_core::{muxing::StreamMuxerBox, transport::dummy::DummyTransport};
7575
use libp2p_identity::PeerId;
76-
use libp2p_swarm::{NetworkBehaviour, Swarm};
76+
use libp2p_swarm::NetworkBehaviour;
7777

7878
#[test]
7979
#[cfg(all(
@@ -524,6 +524,7 @@ mod tests {
524524
feature = "dns",
525525
feature = "relay",
526526
feature = "websocket",
527+
feature = "metrics",
527528
))]
528529
async fn all() {
529530
#[derive(NetworkBehaviour)]
@@ -532,7 +533,7 @@ mod tests {
532533
relay: libp2p_relay::client::Behaviour,
533534
}
534535

535-
let (builder, _bandwidth_sinks) = SwarmBuilder::with_new_identity()
536+
let _ = SwarmBuilder::with_new_identity()
536537
.with_tokio()
537538
.with_tcp(
538539
Default::default(),
@@ -548,26 +549,23 @@ mod tests {
548549
.unwrap()
549550
.with_relay_client(libp2p_tls::Config::new, libp2p_yamux::Config::default)
550551
.unwrap()
551-
.with_bandwidth_logging();
552-
let _: Swarm<MyBehaviour> = builder
552+
.with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
553553
.with_behaviour(|_key, relay| MyBehaviour { relay })
554554
.unwrap()
555555
.build();
556556
}
557557

558558
#[test]
559559
#[cfg(all(feature = "tokio", feature = "tcp", feature = "tls", feature = "yamux"))]
560-
fn tcp_bandwidth_logging() -> Result<(), Box<dyn std::error::Error>> {
561-
let (builder, _logging) = SwarmBuilder::with_new_identity()
560+
fn tcp_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
561+
let _ = SwarmBuilder::with_new_identity()
562562
.with_tokio()
563563
.with_tcp(
564564
Default::default(),
565565
libp2p_tls::Config::new,
566566
libp2p_yamux::Config::default,
567567
)?
568-
.with_bandwidth_logging();
569-
570-
builder
568+
.with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
571569
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
572570
.unwrap()
573571
.build();
@@ -577,13 +575,11 @@ mod tests {
577575

578576
#[test]
579577
#[cfg(all(feature = "tokio", feature = "quic"))]
580-
fn quic_bandwidth_logging() -> Result<(), Box<dyn std::error::Error>> {
581-
let (builder, _logging) = SwarmBuilder::with_new_identity()
578+
fn quic_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
579+
let _ = SwarmBuilder::with_new_identity()
582580
.with_tokio()
583581
.with_quic()
584-
.with_bandwidth_logging();
585-
586-
builder
582+
.with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
587583
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
588584
.unwrap()
589585
.build();
@@ -593,13 +589,11 @@ mod tests {
593589

594590
#[test]
595591
#[cfg(feature = "tokio")]
596-
fn other_transport_bandwidth_logging() -> Result<(), Box<dyn std::error::Error>> {
597-
let (builder, _logging) = SwarmBuilder::with_new_identity()
592+
fn other_transport_bandwidth_metrics() -> Result<(), Box<dyn std::error::Error>> {
593+
let _ = SwarmBuilder::with_new_identity()
598594
.with_tokio()
599595
.with_other_transport(|_| DummyTransport::<(PeerId, StreamMuxerBox)>::new())?
600-
.with_bandwidth_logging();
601-
602-
builder
596+
.with_bandwidth_metrics(&mut libp2p_metrics::Registry::default())
603597
.with_behaviour(|_| libp2p_swarm::dummy::Behaviour)
604598
.unwrap()
605599
.build();

libp2p/src/builder/phase.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![allow(unused_imports)]
22

33
mod bandwidth_logging;
4+
mod bandwidth_metrics;
45
mod behaviour;
56
mod build;
67
mod dns;
@@ -14,6 +15,7 @@ mod tcp;
1415
mod websocket;
1516

1617
use bandwidth_logging::*;
18+
use bandwidth_metrics::*;
1719
use behaviour::*;
1820
use build::*;
1921
use dns::*;

libp2p/src/builder/phase/bandwidth_logging.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
#[allow(deprecated)]
23
use crate::bandwidth::BandwidthSinks;
34
use crate::transport_ext::TransportExt;
45
use crate::SwarmBuilder;
@@ -13,16 +14,18 @@ pub struct BandwidthLoggingPhase<T, R> {
1314
impl<T: AuthenticatedMultiplexedTransport, Provider, R>
1415
SwarmBuilder<Provider, BandwidthLoggingPhase<T, R>>
1516
{
17+
#[allow(deprecated)]
18+
#[deprecated(note = "Use `with_bandwidth_metrics` instead.")]
1619
pub fn with_bandwidth_logging(
1720
self,
1821
) -> (
19-
SwarmBuilder<Provider, BehaviourPhase<impl AuthenticatedMultiplexedTransport, R>>,
22+
SwarmBuilder<Provider, BandwidthMetricsPhase<impl AuthenticatedMultiplexedTransport, R>>,
2023
Arc<BandwidthSinks>,
2124
) {
2225
let (transport, sinks) = self.phase.transport.with_bandwidth_logging();
2326
(
2427
SwarmBuilder {
25-
phase: BehaviourPhase {
28+
phase: BandwidthMetricsPhase {
2629
relay_behaviour: self.phase.relay_behaviour,
2730
transport,
2831
},
@@ -33,9 +36,9 @@ impl<T: AuthenticatedMultiplexedTransport, Provider, R>
3336
)
3437
}
3538

36-
pub fn without_bandwidth_logging(self) -> SwarmBuilder<Provider, BehaviourPhase<T, R>> {
39+
pub fn without_bandwidth_logging(self) -> SwarmBuilder<Provider, BandwidthMetricsPhase<T, R>> {
3740
SwarmBuilder {
38-
phase: BehaviourPhase {
41+
phase: BandwidthMetricsPhase {
3942
relay_behaviour: self.phase.relay_behaviour,
4043
transport: self.phase.transport,
4144
},
@@ -46,6 +49,18 @@ impl<T: AuthenticatedMultiplexedTransport, Provider, R>
4649
}
4750

4851
// Shortcuts
52+
#[cfg(feature = "metrics")]
53+
impl<Provider, T: AuthenticatedMultiplexedTransport, R>
54+
SwarmBuilder<Provider, BandwidthLoggingPhase<T, R>>
55+
{
56+
pub fn with_bandwidth_metrics(
57+
self,
58+
registry: &mut libp2p_metrics::Registry,
59+
) -> SwarmBuilder<Provider, BehaviourPhase<impl AuthenticatedMultiplexedTransport, R>> {
60+
self.without_bandwidth_logging()
61+
.with_bandwidth_metrics(registry)
62+
}
63+
}
4964
#[cfg(feature = "relay")]
5065
impl<Provider, T: AuthenticatedMultiplexedTransport>
5166
SwarmBuilder<Provider, BandwidthLoggingPhase<T, libp2p_relay::client::Behaviour>>
@@ -54,17 +69,20 @@ impl<Provider, T: AuthenticatedMultiplexedTransport>
5469
self,
5570
constructor: impl FnOnce(&libp2p_identity::Keypair, libp2p_relay::client::Behaviour) -> R,
5671
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
57-
self.without_bandwidth_logging().with_behaviour(constructor)
72+
self.without_bandwidth_logging()
73+
.without_bandwidth_metrics()
74+
.with_behaviour(constructor)
5875
}
5976
}
60-
6177
impl<Provider, T: AuthenticatedMultiplexedTransport>
6278
SwarmBuilder<Provider, BandwidthLoggingPhase<T, NoRelayBehaviour>>
6379
{
6480
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
6581
self,
6682
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
6783
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
68-
self.without_bandwidth_logging().with_behaviour(constructor)
84+
self.without_bandwidth_logging()
85+
.without_bandwidth_metrics()
86+
.with_behaviour(constructor)
6987
}
7088
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use super::*;
2+
#[allow(deprecated)]
3+
use crate::bandwidth::BandwidthSinks;
4+
use crate::transport_ext::TransportExt;
5+
use crate::SwarmBuilder;
6+
use std::marker::PhantomData;
7+
use std::sync::Arc;
8+
9+
pub struct BandwidthMetricsPhase<T, R> {
10+
pub(crate) relay_behaviour: R,
11+
pub(crate) transport: T,
12+
}
13+
14+
#[cfg(feature = "metrics")]
15+
impl<T: AuthenticatedMultiplexedTransport, Provider, R>
16+
SwarmBuilder<Provider, BandwidthMetricsPhase<T, R>>
17+
{
18+
pub fn with_bandwidth_metrics(
19+
self,
20+
registry: &mut libp2p_metrics::Registry,
21+
) -> SwarmBuilder<Provider, BehaviourPhase<impl AuthenticatedMultiplexedTransport, R>> {
22+
SwarmBuilder {
23+
phase: BehaviourPhase {
24+
relay_behaviour: self.phase.relay_behaviour,
25+
transport: libp2p_metrics::BandwidthTransport::new(self.phase.transport, registry)
26+
.map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn))),
27+
},
28+
keypair: self.keypair,
29+
phantom: PhantomData,
30+
}
31+
}
32+
}
33+
34+
impl<T, Provider, R> SwarmBuilder<Provider, BandwidthMetricsPhase<T, R>> {
35+
pub fn without_bandwidth_metrics(self) -> SwarmBuilder<Provider, BehaviourPhase<T, R>> {
36+
SwarmBuilder {
37+
phase: BehaviourPhase {
38+
relay_behaviour: self.phase.relay_behaviour,
39+
transport: self.phase.transport,
40+
},
41+
keypair: self.keypair,
42+
phantom: PhantomData,
43+
}
44+
}
45+
}
46+
47+
// Shortcuts
48+
#[cfg(feature = "relay")]
49+
impl<Provider, T: AuthenticatedMultiplexedTransport>
50+
SwarmBuilder<Provider, BandwidthMetricsPhase<T, libp2p_relay::client::Behaviour>>
51+
{
52+
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
53+
self,
54+
constructor: impl FnOnce(&libp2p_identity::Keypair, libp2p_relay::client::Behaviour) -> R,
55+
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
56+
self.without_bandwidth_metrics().with_behaviour(constructor)
57+
}
58+
}
59+
60+
impl<Provider, T: AuthenticatedMultiplexedTransport>
61+
SwarmBuilder<Provider, BandwidthMetricsPhase<T, NoRelayBehaviour>>
62+
{
63+
pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
64+
self,
65+
constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
66+
) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
67+
self.without_bandwidth_metrics().with_behaviour(constructor)
68+
}
69+
}

0 commit comments

Comments
 (0)