2021-08-13 22:51:54 +02:00
|
|
|
// Copyright 2021 Protocol Labs.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2022-11-15 15:45:14 -05:00
|
|
|
use crate::protocol_stack;
|
2023-03-13 01:46:58 +11:00
|
|
|
use libp2p_identity::PeerId;
|
2023-01-03 20:42:32 +01:00
|
|
|
use prometheus_client::encoding::{EncodeLabelSet, EncodeMetric, MetricEncoder};
|
2022-02-03 11:31:41 +01:00
|
|
|
use prometheus_client::metrics::counter::Counter;
|
2022-11-15 15:45:14 -05:00
|
|
|
use prometheus_client::metrics::family::Family;
|
2022-02-03 11:31:41 +01:00
|
|
|
use prometheus_client::metrics::histogram::{exponential_buckets, Histogram};
|
2022-07-15 09:16:03 +02:00
|
|
|
use prometheus_client::metrics::MetricType;
|
2022-02-03 11:31:41 +01:00
|
|
|
use prometheus_client::registry::Registry;
|
2022-07-15 09:16:03 +02:00
|
|
|
use std::collections::HashMap;
|
2021-08-13 22:51:54 +02:00
|
|
|
use std::iter;
|
2022-07-15 09:16:03 +02:00
|
|
|
use std::sync::{Arc, Mutex};
|
2021-08-13 22:51:54 +02:00
|
|
|
|
|
|
|
pub struct Metrics {
|
2022-07-15 09:16:03 +02:00
|
|
|
protocols: Protocols,
|
2021-08-13 22:51:54 +02:00
|
|
|
error: Counter,
|
|
|
|
pushed: Counter,
|
|
|
|
received: Counter,
|
|
|
|
received_info_listen_addrs: Histogram,
|
|
|
|
received_info_protocols: Histogram,
|
|
|
|
sent: Counter,
|
2022-11-15 15:45:14 -05:00
|
|
|
listen_addresses: Family<AddressLabels, Counter>,
|
2021-08-13 22:51:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Metrics {
|
|
|
|
pub fn new(registry: &mut Registry) -> Self {
|
|
|
|
let sub_registry = registry.sub_registry_with_prefix("identify");
|
|
|
|
|
2022-07-15 09:16:03 +02:00
|
|
|
let protocols = Protocols::default();
|
|
|
|
sub_registry.register(
|
|
|
|
"protocols",
|
|
|
|
"Number of connected nodes supporting a specific protocol, with \
|
|
|
|
\"unrecognized\" for each peer supporting one or more unrecognized \
|
|
|
|
protocols",
|
2023-01-03 20:42:32 +01:00
|
|
|
protocols.clone(),
|
2022-07-15 09:16:03 +02:00
|
|
|
);
|
|
|
|
|
2021-08-13 22:51:54 +02:00
|
|
|
let error = Counter::default();
|
|
|
|
sub_registry.register(
|
|
|
|
"errors",
|
|
|
|
"Number of errors while attempting to identify the remote",
|
2023-01-03 20:42:32 +01:00
|
|
|
error.clone(),
|
2021-08-13 22:51:54 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
let pushed = Counter::default();
|
|
|
|
sub_registry.register(
|
|
|
|
"pushed",
|
|
|
|
"Number of times identification information of the local node has \
|
|
|
|
been actively pushed to a peer.",
|
2023-01-03 20:42:32 +01:00
|
|
|
pushed.clone(),
|
2021-08-13 22:51:54 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
let received = Counter::default();
|
|
|
|
sub_registry.register(
|
|
|
|
"received",
|
|
|
|
"Number of times identification information has been received from \
|
|
|
|
a peer",
|
2023-01-03 20:42:32 +01:00
|
|
|
received.clone(),
|
2021-08-13 22:51:54 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
let received_info_listen_addrs =
|
|
|
|
Histogram::new(iter::once(0.0).chain(exponential_buckets(1.0, 2.0, 9)));
|
|
|
|
sub_registry.register(
|
|
|
|
"received_info_listen_addrs",
|
|
|
|
"Number of listen addresses for remote peer received in \
|
|
|
|
identification information",
|
2023-01-03 20:42:32 +01:00
|
|
|
received_info_listen_addrs.clone(),
|
2021-08-13 22:51:54 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
let received_info_protocols =
|
|
|
|
Histogram::new(iter::once(0.0).chain(exponential_buckets(1.0, 2.0, 9)));
|
|
|
|
sub_registry.register(
|
|
|
|
"received_info_protocols",
|
|
|
|
"Number of protocols supported by the remote peer received in \
|
|
|
|
identification information",
|
2023-01-03 20:42:32 +01:00
|
|
|
received_info_protocols.clone(),
|
2021-08-13 22:51:54 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
let sent = Counter::default();
|
|
|
|
sub_registry.register(
|
|
|
|
"sent",
|
|
|
|
"Number of times identification information of the local node has \
|
|
|
|
been sent to a peer in response to an identification request",
|
2023-01-03 20:42:32 +01:00
|
|
|
sent.clone(),
|
2021-08-13 22:51:54 +02:00
|
|
|
);
|
|
|
|
|
2022-11-15 15:45:14 -05:00
|
|
|
let listen_addresses = Family::default();
|
|
|
|
sub_registry.register(
|
|
|
|
"listen_addresses",
|
|
|
|
"Number of listen addresses for remote peer per protocol stack",
|
2023-01-03 20:42:32 +01:00
|
|
|
listen_addresses.clone(),
|
2022-11-15 15:45:14 -05:00
|
|
|
);
|
|
|
|
|
2021-08-13 22:51:54 +02:00
|
|
|
Self {
|
2022-07-15 09:16:03 +02:00
|
|
|
protocols,
|
2021-08-13 22:51:54 +02:00
|
|
|
error,
|
|
|
|
pushed,
|
|
|
|
received,
|
|
|
|
received_info_listen_addrs,
|
|
|
|
received_info_protocols,
|
|
|
|
sent,
|
2022-11-15 15:45:14 -05:00
|
|
|
listen_addresses,
|
2021-08-13 22:51:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 01:17:31 +01:00
|
|
|
impl super::Recorder<libp2p_identify::Event> for Metrics {
|
|
|
|
fn record(&self, event: &libp2p_identify::Event) {
|
2021-08-13 22:51:54 +02:00
|
|
|
match event {
|
2022-10-04 01:17:31 +01:00
|
|
|
libp2p_identify::Event::Error { .. } => {
|
2022-07-15 09:16:03 +02:00
|
|
|
self.error.inc();
|
2021-08-13 22:51:54 +02:00
|
|
|
}
|
2022-10-04 01:17:31 +01:00
|
|
|
libp2p_identify::Event::Pushed { .. } => {
|
2022-07-15 09:16:03 +02:00
|
|
|
self.pushed.inc();
|
2021-08-13 22:51:54 +02:00
|
|
|
}
|
2022-10-04 01:17:31 +01:00
|
|
|
libp2p_identify::Event::Received { peer_id, info, .. } => {
|
2022-07-15 09:16:03 +02:00
|
|
|
{
|
|
|
|
let mut protocols: Vec<String> = info
|
|
|
|
.protocols
|
|
|
|
.iter()
|
|
|
|
.filter(|p| {
|
|
|
|
let allowed_protocols: &[&[u8]] = &[
|
|
|
|
#[cfg(feature = "dcutr")]
|
|
|
|
libp2p_dcutr::PROTOCOL_NAME,
|
|
|
|
// #[cfg(feature = "gossipsub")]
|
|
|
|
// #[cfg(not(target_os = "unknown"))]
|
|
|
|
// TODO: Add Gossipsub protocol name
|
|
|
|
libp2p_identify::PROTOCOL_NAME,
|
|
|
|
libp2p_identify::PUSH_PROTOCOL_NAME,
|
|
|
|
#[cfg(feature = "kad")]
|
|
|
|
libp2p_kad::protocol::DEFAULT_PROTO_NAME,
|
|
|
|
#[cfg(feature = "ping")]
|
|
|
|
libp2p_ping::PROTOCOL_NAME,
|
|
|
|
#[cfg(feature = "relay")]
|
2023-01-02 20:21:46 +00:00
|
|
|
libp2p_relay::STOP_PROTOCOL_NAME,
|
2022-07-15 09:16:03 +02:00
|
|
|
#[cfg(feature = "relay")]
|
2023-01-02 20:21:46 +00:00
|
|
|
libp2p_relay::HOP_PROTOCOL_NAME,
|
2022-07-15 09:16:03 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
allowed_protocols.contains(&p.as_bytes())
|
|
|
|
})
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
// Signal via an additional label value that one or more
|
|
|
|
// protocols of the remote peer have not been recognized.
|
|
|
|
if protocols.len() < info.protocols.len() {
|
|
|
|
protocols.push("unrecognized".to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
protocols.sort_unstable();
|
|
|
|
protocols.dedup();
|
|
|
|
|
|
|
|
self.protocols.add(*peer_id, protocols);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.received.inc();
|
|
|
|
self.received_info_protocols
|
2021-08-13 22:51:54 +02:00
|
|
|
.observe(info.protocols.len() as f64);
|
2022-07-15 09:16:03 +02:00
|
|
|
self.received_info_listen_addrs
|
2021-08-13 22:51:54 +02:00
|
|
|
.observe(info.listen_addrs.len() as f64);
|
2022-11-15 15:45:14 -05:00
|
|
|
for listen_addr in &info.listen_addrs {
|
|
|
|
self.listen_addresses
|
|
|
|
.get_or_create(&AddressLabels {
|
|
|
|
protocols: protocol_stack::as_string(listen_addr),
|
|
|
|
})
|
|
|
|
.inc();
|
|
|
|
}
|
2021-08-13 22:51:54 +02:00
|
|
|
}
|
2022-10-04 01:17:31 +01:00
|
|
|
libp2p_identify::Event::Sent { .. } => {
|
2022-07-15 09:16:03 +02:00
|
|
|
self.sent.inc();
|
2021-08-13 22:51:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-15 09:16:03 +02:00
|
|
|
|
|
|
|
impl<TBvEv, THandleErr> super::Recorder<libp2p_swarm::SwarmEvent<TBvEv, THandleErr>> for Metrics {
|
|
|
|
fn record(&self, event: &libp2p_swarm::SwarmEvent<TBvEv, THandleErr>) {
|
|
|
|
if let libp2p_swarm::SwarmEvent::ConnectionClosed {
|
|
|
|
peer_id,
|
|
|
|
num_established,
|
|
|
|
..
|
|
|
|
} = event
|
|
|
|
{
|
|
|
|
if *num_established == 0 {
|
|
|
|
self.protocols.remove(*peer_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-03 20:42:32 +01:00
|
|
|
#[derive(EncodeLabelSet, Hash, Clone, Eq, PartialEq, Debug)]
|
2022-11-15 15:45:14 -05:00
|
|
|
struct AddressLabels {
|
|
|
|
protocols: String,
|
|
|
|
}
|
|
|
|
|
2023-01-03 20:42:32 +01:00
|
|
|
#[derive(Default, Clone, Debug)]
|
2022-07-15 09:16:03 +02:00
|
|
|
struct Protocols {
|
|
|
|
peers: Arc<Mutex<HashMap<PeerId, Vec<String>>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Protocols {
|
|
|
|
fn add(&self, peer: PeerId, protocols: Vec<String>) {
|
|
|
|
self.peers
|
|
|
|
.lock()
|
|
|
|
.expect("Lock not to be poisoned")
|
|
|
|
.insert(peer, protocols);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn remove(&self, peer: PeerId) {
|
|
|
|
self.peers
|
|
|
|
.lock()
|
|
|
|
.expect("Lock not to be poisoned")
|
|
|
|
.remove(&peer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EncodeMetric for Protocols {
|
2023-01-03 20:42:32 +01:00
|
|
|
fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> {
|
2022-07-15 09:16:03 +02:00
|
|
|
let count_by_protocol = self
|
|
|
|
.peers
|
|
|
|
.lock()
|
|
|
|
.expect("Lock not to be poisoned")
|
|
|
|
.iter()
|
|
|
|
.fold(
|
2023-01-03 20:42:32 +01:00
|
|
|
HashMap::<String, i64>::default(),
|
2022-07-15 09:16:03 +02:00
|
|
|
|mut acc, (_, protocols)| {
|
|
|
|
for protocol in protocols {
|
|
|
|
let count = acc.entry(protocol.to_string()).or_default();
|
2022-07-25 10:45:43 +02:00
|
|
|
*count += 1;
|
2022-07-15 09:16:03 +02:00
|
|
|
}
|
|
|
|
acc
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
for (protocol, count) in count_by_protocol {
|
|
|
|
encoder
|
2023-01-03 20:42:32 +01:00
|
|
|
.encode_family(&[("protocol", protocol)])?
|
|
|
|
.encode_gauge(&count)?;
|
2022-07-15 09:16:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn metric_type(&self) -> MetricType {
|
|
|
|
MetricType::Gauge
|
|
|
|
}
|
|
|
|
}
|