Skip to content

Commit 69efe63

Browse files
misc/metrics: Add protocols label to address-specific metrics (#2982)
Previously, we would only track the metrics like the number of open connections. With this patch, we extend these metrics with a `protocols` label that contains a "protocol stack". A protocol stack is a multi-address with all variable parts removed. For example, `/ip4/127.0.0.1/tcp/1234` turns into `/ip4/tcp`. Resolves #2758.
1 parent d5ea93d commit 69efe63

File tree

6 files changed

+138
-26
lines changed

6 files changed

+138
-26
lines changed

misc/metrics/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
- Update to `libp2p-gossipsub` `v0.43.0`.
1818

19+
- Add `protocol_stack` metrics. See [PR 2982].
20+
21+
[PR 2982]: https://github.com/libp2p/rust-libp2p/pull/2982/
22+
1923
# 0.10.0
2024

2125
- Update to `libp2p-swarm` `v0.40.0`.

misc/metrics/examples/metrics/main.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use futures::stream::StreamExt;
5454
use libp2p::core::Multiaddr;
5555
use libp2p::metrics::{Metrics, Recorder};
5656
use libp2p::swarm::{NetworkBehaviour, SwarmEvent};
57-
use libp2p::{identity, ping, PeerId, Swarm};
57+
use libp2p::{identify, identity, ping, PeerId, Swarm};
5858
use libp2p_swarm::keep_alive;
5959
use log::info;
6060
use prometheus_client::registry::Registry;
@@ -68,11 +68,12 @@ fn main() -> Result<(), Box<dyn Error>> {
6868

6969
let local_key = identity::Keypair::generate_ed25519();
7070
let local_peer_id = PeerId::from(local_key.public());
71+
let local_pub_key = local_key.public();
7172
info!("Local peer id: {:?}", local_peer_id);
7273

7374
let mut swarm = Swarm::without_executor(
7475
block_on(libp2p::development_transport(local_key))?,
75-
Behaviour::default(),
76+
Behaviour::new(local_pub_key),
7677
local_peer_id,
7778
);
7879

@@ -95,6 +96,10 @@ fn main() -> Result<(), Box<dyn Error>> {
9596
info!("{:?}", ping_event);
9697
metrics.record(&ping_event);
9798
}
99+
SwarmEvent::Behaviour(BehaviourEvent::Identify(identify_event)) => {
100+
info!("{:?}", identify_event);
101+
metrics.record(&identify_event);
102+
}
98103
swarm_event => {
99104
info!("{:?}", swarm_event);
100105
metrics.record(&swarm_event);
@@ -109,8 +114,22 @@ fn main() -> Result<(), Box<dyn Error>> {
109114
///
110115
/// For illustrative purposes, this includes the [`keep_alive::Behaviour`]) behaviour so the ping actually happen
111116
/// and can be observed via the metrics.
112-
#[derive(NetworkBehaviour, Default)]
117+
#[derive(NetworkBehaviour)]
113118
struct Behaviour {
119+
identify: identify::Behaviour,
114120
keep_alive: keep_alive::Behaviour,
115121
ping: ping::Behaviour,
116122
}
123+
124+
impl Behaviour {
125+
fn new(local_pub_key: libp2p::identity::PublicKey) -> Self {
126+
Self {
127+
ping: ping::Behaviour::default(),
128+
identify: identify::Behaviour::new(identify::Config::new(
129+
"/ipfs/0.1.0".into(),
130+
local_pub_key,
131+
)),
132+
keep_alive: keep_alive::Behaviour::default(),
133+
}
134+
}
135+
}

misc/metrics/src/identify.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919
// DEALINGS IN THE SOFTWARE.
2020

21+
use crate::protocol_stack;
2122
use libp2p_core::PeerId;
22-
use prometheus_client::encoding::text::{EncodeMetric, Encoder};
23+
use prometheus_client::encoding::text::{Encode, EncodeMetric, Encoder};
2324
use prometheus_client::metrics::counter::Counter;
25+
use prometheus_client::metrics::family::Family;
2426
use prometheus_client::metrics::histogram::{exponential_buckets, Histogram};
2527
use prometheus_client::metrics::MetricType;
2628
use prometheus_client::registry::Registry;
@@ -36,6 +38,7 @@ pub struct Metrics {
3638
received_info_listen_addrs: Histogram,
3739
received_info_protocols: Histogram,
3840
sent: Counter,
41+
listen_addresses: Family<AddressLabels, Counter>,
3942
}
4043

4144
impl Metrics {
@@ -100,6 +103,13 @@ impl Metrics {
100103
Box::new(sent.clone()),
101104
);
102105

106+
let listen_addresses = Family::default();
107+
sub_registry.register(
108+
"listen_addresses",
109+
"Number of listen addresses for remote peer per protocol stack",
110+
Box::new(listen_addresses.clone()),
111+
);
112+
103113
Self {
104114
protocols,
105115
error,
@@ -108,6 +118,7 @@ impl Metrics {
108118
received_info_listen_addrs,
109119
received_info_protocols,
110120
sent,
121+
listen_addresses,
111122
}
112123
}
113124
}
@@ -167,6 +178,13 @@ impl super::Recorder<libp2p_identify::Event> for Metrics {
167178
.observe(info.protocols.len() as f64);
168179
self.received_info_listen_addrs
169180
.observe(info.listen_addrs.len() as f64);
181+
for listen_addr in &info.listen_addrs {
182+
self.listen_addresses
183+
.get_or_create(&AddressLabels {
184+
protocols: protocol_stack::as_string(listen_addr),
185+
})
186+
.inc();
187+
}
170188
}
171189
libp2p_identify::Event::Sent { .. } => {
172190
self.sent.inc();
@@ -190,6 +208,11 @@ impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleE
190208
}
191209
}
192210

211+
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
212+
struct AddressLabels {
213+
protocols: String,
214+
}
215+
193216
#[derive(Default, Clone)]
194217
struct Protocols {
195218
peers: Arc<Mutex<HashMap<PeerId, Vec<String>>>>,

misc/metrics/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ mod identify;
3838
mod kad;
3939
#[cfg(feature = "ping")]
4040
mod ping;
41+
mod protocol_stack;
4142
#[cfg(feature = "relay")]
4243
mod relay;
4344
mod swarm;

misc/metrics/src/protocol_stack.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use libp2p_core::multiaddr::Multiaddr;
2+
3+
pub fn as_string(ma: &Multiaddr) -> String {
4+
let len = ma
5+
.protocol_stack()
6+
.fold(0, |acc, proto| acc + proto.len() + 1);
7+
let mut protocols = String::with_capacity(len);
8+
for proto_tag in ma.protocol_stack() {
9+
protocols.push('/');
10+
protocols.push_str(proto_tag);
11+
}
12+
protocols
13+
}
14+
15+
#[cfg(test)]
16+
mod tests {
17+
use super::*;
18+
19+
#[test]
20+
fn ip6_tcp_wss_p2p() {
21+
let ma = Multiaddr::try_from("/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/wss/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC").expect("testbad");
22+
23+
let protocol_stack = as_string(&ma);
24+
25+
assert_eq!(protocol_stack, "/ip6/tcp/wss/p2p");
26+
}
27+
}

misc/metrics/src/swarm.rs

+60-22
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,38 @@
1818
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919
// DEALINGS IN THE SOFTWARE.
2020

21+
use crate::protocol_stack;
2122
use prometheus_client::encoding::text::Encode;
2223
use prometheus_client::metrics::counter::Counter;
2324
use prometheus_client::metrics::family::Family;
2425
use prometheus_client::registry::Registry;
2526

2627
pub struct Metrics {
27-
connections_incoming: Counter,
28+
connections_incoming: Family<AddressLabels, Counter>,
2829
connections_incoming_error: Family<IncomingConnectionErrorLabels, Counter>,
2930

3031
connections_established: Family<ConnectionEstablishedLabels, Counter>,
3132
connections_closed: Family<ConnectionClosedLabels, Counter>,
3233

33-
new_listen_addr: Counter,
34-
expired_listen_addr: Counter,
34+
new_listen_addr: Family<AddressLabels, Counter>,
35+
expired_listen_addr: Family<AddressLabels, Counter>,
3536

36-
listener_closed: Counter,
37+
listener_closed: Family<AddressLabels, Counter>,
3738
listener_error: Counter,
3839

3940
dial_attempt: Counter,
4041
outgoing_connection_error: Family<OutgoingConnectionErrorLabels, Counter>,
41-
connected_to_banned_peer: Counter,
42+
connected_to_banned_peer: Family<AddressLabels, Counter>,
4243
}
4344

4445
impl Metrics {
4546
pub fn new(registry: &mut Registry) -> Self {
4647
let sub_registry = registry.sub_registry_with_prefix("swarm");
4748

48-
let connections_incoming = Counter::default();
49+
let connections_incoming = Family::default();
4950
sub_registry.register(
5051
"connections_incoming",
51-
"Number of incoming connections",
52+
"Number of incoming connections per address stack",
5253
Box::new(connections_incoming.clone()),
5354
);
5455

@@ -59,21 +60,21 @@ impl Metrics {
5960
Box::new(connections_incoming_error.clone()),
6061
);
6162

62-
let new_listen_addr = Counter::default();
63+
let new_listen_addr = Family::default();
6364
sub_registry.register(
6465
"new_listen_addr",
6566
"Number of new listen addresses",
6667
Box::new(new_listen_addr.clone()),
6768
);
6869

69-
let expired_listen_addr = Counter::default();
70+
let expired_listen_addr = Family::default();
7071
sub_registry.register(
7172
"expired_listen_addr",
7273
"Number of expired listen addresses",
7374
Box::new(expired_listen_addr.clone()),
7475
);
7576

76-
let listener_closed = Counter::default();
77+
let listener_closed = Family::default();
7778
sub_registry.register(
7879
"listener_closed",
7980
"Number of listeners closed",
@@ -101,7 +102,7 @@ impl Metrics {
101102
Box::new(outgoing_connection_error.clone()),
102103
);
103104

104-
let connected_to_banned_peer = Counter::default();
105+
let connected_to_banned_peer = Family::default();
105106
sub_registry.register(
106107
"connected_to_banned_peer",
107108
"Number of connection attempts to banned peer",
@@ -146,23 +147,34 @@ impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleE
146147
self.connections_established
147148
.get_or_create(&ConnectionEstablishedLabels {
148149
role: endpoint.into(),
150+
protocols: protocol_stack::as_string(endpoint.get_remote_address()),
149151
})
150152
.inc();
151153
}
152154
libp2p_swarm::SwarmEvent::ConnectionClosed { endpoint, .. } => {
153155
self.connections_closed
154156
.get_or_create(&ConnectionClosedLabels {
155157
role: endpoint.into(),
158+
protocols: protocol_stack::as_string(endpoint.get_remote_address()),
156159
})
157160
.inc();
158161
}
159-
libp2p_swarm::SwarmEvent::IncomingConnection { .. } => {
160-
self.connections_incoming.inc();
162+
libp2p_swarm::SwarmEvent::IncomingConnection { send_back_addr, .. } => {
163+
self.connections_incoming
164+
.get_or_create(&AddressLabels {
165+
protocols: protocol_stack::as_string(send_back_addr),
166+
})
167+
.inc();
161168
}
162-
libp2p_swarm::SwarmEvent::IncomingConnectionError { error, .. } => {
169+
libp2p_swarm::SwarmEvent::IncomingConnectionError {
170+
error,
171+
send_back_addr,
172+
..
173+
} => {
163174
self.connections_incoming_error
164175
.get_or_create(&IncomingConnectionErrorLabels {
165176
error: error.into(),
177+
protocols: protocol_stack::as_string(send_back_addr),
166178
})
167179
.inc();
168180
}
@@ -221,17 +233,35 @@ impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleE
221233
}
222234
};
223235
}
224-
libp2p_swarm::SwarmEvent::BannedPeer { .. } => {
225-
self.connected_to_banned_peer.inc();
236+
libp2p_swarm::SwarmEvent::BannedPeer { endpoint, .. } => {
237+
self.connected_to_banned_peer
238+
.get_or_create(&AddressLabels {
239+
protocols: protocol_stack::as_string(endpoint.get_remote_address()),
240+
})
241+
.inc();
226242
}
227-
libp2p_swarm::SwarmEvent::NewListenAddr { .. } => {
228-
self.new_listen_addr.inc();
243+
libp2p_swarm::SwarmEvent::NewListenAddr { address, .. } => {
244+
self.new_listen_addr
245+
.get_or_create(&AddressLabels {
246+
protocols: protocol_stack::as_string(address),
247+
})
248+
.inc();
229249
}
230-
libp2p_swarm::SwarmEvent::ExpiredListenAddr { .. } => {
231-
self.expired_listen_addr.inc();
250+
libp2p_swarm::SwarmEvent::ExpiredListenAddr { address, .. } => {
251+
self.expired_listen_addr
252+
.get_or_create(&AddressLabels {
253+
protocols: protocol_stack::as_string(address),
254+
})
255+
.inc();
232256
}
233-
libp2p_swarm::SwarmEvent::ListenerClosed { .. } => {
234-
self.listener_closed.inc();
257+
libp2p_swarm::SwarmEvent::ListenerClosed { addresses, .. } => {
258+
for address in addresses {
259+
self.listener_closed
260+
.get_or_create(&AddressLabels {
261+
protocols: protocol_stack::as_string(address),
262+
})
263+
.inc();
264+
}
235265
}
236266
libp2p_swarm::SwarmEvent::ListenerError { .. } => {
237267
self.listener_error.inc();
@@ -246,11 +276,18 @@ impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleE
246276
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
247277
struct ConnectionEstablishedLabels {
248278
role: Role,
279+
protocols: String,
249280
}
250281

251282
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
252283
struct ConnectionClosedLabels {
253284
role: Role,
285+
protocols: String,
286+
}
287+
288+
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
289+
struct AddressLabels {
290+
protocols: String,
254291
}
255292

256293
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
@@ -298,6 +335,7 @@ enum OutgoingConnectionErrorError {
298335
#[derive(Encode, Hash, Clone, Eq, PartialEq)]
299336
struct IncomingConnectionErrorLabels {
300337
error: PendingInboundConnectionError,
338+
protocols: String,
301339
}
302340

303341
#[derive(Encode, Hash, Clone, Eq, PartialEq)]

0 commit comments

Comments
 (0)