diff --git a/client/src/main.rs b/client/src/main.rs index 12f2a0ae6..77d69aa96 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -80,6 +80,7 @@ async fn run( let ot_metrics = Arc::new( telemetry::otlp::initialize( metric_attributes, + cfg.project_name.clone(), &cfg.origin, &cfg.libp2p.kademlia.operation_mode.into(), cfg.otel.clone(), @@ -89,6 +90,7 @@ async fn run( let (p2p_client, p2p_event_loop, event_receiver) = p2p::init( cfg.libp2p.clone(), + cfg.project_name.clone(), id_keys, version, &cfg.genesis_hash, diff --git a/core/src/network/p2p.rs b/core/src/network/p2p.rs index 231ccddc5..987629348 100644 --- a/core/src/network/p2p.rs +++ b/core/src/network/p2p.rs @@ -52,7 +52,7 @@ use libp2p_allow_block_list as allow_block_list; const MINIMUM_SUPPORTED_BOOTSTRAP_VERSION: &str = "0.1.1"; const MINIMUM_SUPPORTED_LIGHT_CLIENT_VERSION: &str = "1.9.2"; const IDENTITY_PROTOCOL: &str = "/avail/light/1.0.0"; -const IDENTITY_AGENT_BASE: &str = "avail-light-client"; +const IDENTITY_AGENT_BASE: &str = "light-client"; const IDENTITY_AGENT_ROLE: &str = "light-client"; const IDENTITY_AGENT_CLIENT_TYPE: &str = "rust-client"; @@ -115,9 +115,9 @@ impl FromStr for AgentVersion { } impl AgentVersion { - fn new(version: &str) -> Self { + fn new(project_name: String, version: &str) -> Self { Self { - base_version: IDENTITY_AGENT_BASE.to_string(), + base_version: format!("{project_name}-{IDENTITY_AGENT_BASE}"), role: IDENTITY_AGENT_ROLE.to_string(), release_version: version.to_string(), client_type: IDENTITY_AGENT_CLIENT_TYPE.to_string(), @@ -197,8 +197,10 @@ fn protocol_name(genesis_hash: &str) -> libp2p::StreamProtocol { .expect("Invalid Kademlia protocol name") } +#[allow(clippy::too_many_arguments)] pub async fn init( cfg: LibP2PConfig, + project_name: String, id_keys: Keypair, version: &str, genesis_hash: &str, @@ -222,7 +224,7 @@ pub async fn init( db.inner(), ); // create Swarm - let swarm = build_swarm(&cfg, version, genesis_hash, &id_keys, store) + let swarm = build_swarm(&cfg, project_name, version, genesis_hash, &id_keys, store) .await .expect("Unable to build swarm."); let (event_sender, event_receiver) = broadcast::channel(1000); @@ -234,6 +236,7 @@ pub async fn init( async fn build_swarm( cfg: &LibP2PConfig, + project_name: String, version: &str, genesis_hash: &str, id_keys: &Keypair, @@ -241,7 +244,7 @@ async fn build_swarm( ) -> Result> { // create Identify Protocol Config let identify_cfg = identify::Config::new(IDENTITY_PROTOCOL.to_string(), id_keys.public()) - .with_agent_version(AgentVersion::new(version).to_string()); + .with_agent_version(AgentVersion::new(project_name, version).to_string()); // create AutoNAT Client Config let autonat_cfg = autonat::Config { diff --git a/core/src/telemetry/mod.rs b/core/src/telemetry/mod.rs index 24f34b65b..1e78c9851 100644 --- a/core/src/telemetry/mod.rs +++ b/core/src/telemetry/mod.rs @@ -29,16 +29,16 @@ impl MetricName for MetricCounter { fn name(&self) -> &'static str { use MetricCounter::*; match self { - Starts => "avail.light.starts", - Up => "avail.light.up", - SessionBlocks => "avail.light.session_blocks", - OutgoingConnectionErrors => "avail.light.outgoing_connection_errors", - IncomingConnectionErrors => "avail.light.incoming_connection_errors", - IncomingConnections => "avail.light.incoming_connections", - EstablishedConnections => "avail.light.established_connections", - IncomingPutRecord => "avail.light.incoming_put_record", - IncomingGetRecord => "avail.light.incoming_get_record", - EventLoopEvent => "avail.light.event_loop_event", + Starts => "light.starts", + Up => "light.up", + SessionBlocks => "light.session_blocks", + OutgoingConnectionErrors => "light.outgoing_connection_errors", + IncomingConnectionErrors => "light.incoming_connection_errors", + IncomingConnections => "light.incoming_connections", + EstablishedConnections => "light.established_connections", + IncomingPutRecord => "light.incoming_put_record", + IncomingGetRecord => "light.incoming_get_record", + EventLoopEvent => "light.event_loop_event", } } } @@ -91,25 +91,25 @@ impl MetricName for MetricValue { use MetricValue::*; match self { - BlockHeight(_) => "avail.light.block.height", - BlockConfidence(_) => "avail.light.block.confidence", - BlockConfidenceThreshold(_) => "avail.light.block.confidence_threshold", - BlockProcessingDelay(_) => "avail.light.block.processing_delay", - - DHTReplicationFactor(_) => "avail.light.dht.replication_factor", - DHTFetched(_) => "avail.light.dht.fetched", - DHTFetchedPercentage(_) => "avail.light.dht.fetched_percentage", - DHTFetchDuration(_) => "avail.light.dht.fetch_duration", - DHTPutDuration(_) => "avail.light.dht.put_duration", - DHTPutSuccess(_) => "avail.light.dht.put_success", - - DHTConnectedPeers(_) => "avail.light.dht.connected_peers", - DHTQueryTimeout(_) => "avail.light.dht.query_timeout", - DHTPingLatency(_) => "avail.light.dht.ping_latency", - - RPCFetched(_) => "avail.light.rpc.fetched", - RPCFetchDuration(_) => "avail.light.rpc.fetch_duration", - RPCCallDuration(_) => "avail.light.rpc.call_duration", + BlockHeight(_) => "light.block.height", + BlockConfidence(_) => "light.block.confidence", + BlockConfidenceThreshold(_) => "light.block.confidence_threshold", + BlockProcessingDelay(_) => "light.block.processing_delay", + + DHTReplicationFactor(_) => "light.dht.replication_factor", + DHTFetched(_) => "light.dht.fetched", + DHTFetchedPercentage(_) => "light.dht.fetched_percentage", + DHTFetchDuration(_) => "light.dht.fetch_duration", + DHTPutDuration(_) => "light.dht.put_duration", + DHTPutSuccess(_) => "light.dht.put_success", + + DHTConnectedPeers(_) => "light.dht.connected_peers", + DHTQueryTimeout(_) => "light.dht.query_timeout", + DHTPingLatency(_) => "light.dht.ping_latency", + + RPCFetched(_) => "light.rpc.fetched", + RPCFetchDuration(_) => "light.rpc.fetch_duration", + RPCCallDuration(_) => "light.rpc.call_duration", } } } diff --git a/core/src/telemetry/otlp.rs b/core/src/telemetry/otlp.rs index f3e874387..fb0bb14da 100644 --- a/core/src/telemetry/otlp.rs +++ b/core/src/telemetry/otlp.rs @@ -20,6 +20,7 @@ use tokio_stream::wrappers::BroadcastStream; #[derive(Debug)] pub struct Metrics { meter: Meter, + project_name: String, origin: Origin, mode: RwLock, multiaddress: RwLock, @@ -41,7 +42,8 @@ impl Metrics { } async fn record_u64(&self, name: &'static str, value: u64) -> Result<()> { - let instrument = self.meter.u64_observable_gauge(name).try_init()?; + let gauge_name = format!("{}.{}", name, self.project_name); + let instrument = self.meter.u64_observable_gauge(gauge_name).try_init()?; let attributes = self.attributes().await; self.meter .register_callback(&[instrument.as_any()], move |observer| { @@ -51,7 +53,8 @@ impl Metrics { } async fn record_f64(&self, name: &'static str, value: f64) -> Result<()> { - let instrument = self.meter.f64_observable_gauge(name).try_init()?; + let gauge_name = format!("{}.{}", name, self.project_name); + let instrument = self.meter.f64_observable_gauge(gauge_name).try_init()?; let attributes = self.attributes().await; self.meter .register_callback(&[instrument.as_any()], move |observer| { @@ -265,7 +268,11 @@ impl super::Metrics for Metrics { } } -fn init_counters(meter: Meter, origin: &Origin) -> HashMap<&'static str, Counter> { +fn init_counters( + meter: Meter, + origin: &Origin, + project_name: String, +) -> HashMap<&'static str, Counter> { [ MetricCounter::Starts, MetricCounter::Up, @@ -280,7 +287,11 @@ fn init_counters(meter: Meter, origin: &Origin) -> HashMap<&'static str, Counter ] .iter() .filter(|counter| MetricCounter::is_allowed(counter, origin)) - .map(|counter| (counter.name(), meter.u64_counter(counter.name()).init())) + .map(|counter| { + let otel_counter_name = format!("{}.{}", project_name, counter.name()); + // Keep the `static str as the local bufer map key, but change the OTel counter name` + (counter.name(), meter.u64_counter(otel_counter_name).init()) + }) .collect() } @@ -307,6 +318,7 @@ impl Default for OtelConfig { pub fn initialize( attributes: Vec<(&str, String)>, + project_name: String, origin: &Origin, mode: &Mode, ot_config: OtelConfig, @@ -336,9 +348,10 @@ pub fn initialize( .collect(); // Initialize counters - they need to persist unlike Gauges that are recreated on every record - let counters = init_counters(meter.clone(), origin); + let counters = init_counters(meter.clone(), origin, project_name.clone()); Ok(Metrics { meter, + project_name, origin: origin.clone(), mode: RwLock::new(*mode), multiaddress: RwLock::new(Multiaddr::empty()), @@ -411,7 +424,7 @@ mod tests { let (m_u64, m_f64) = flatten_metrics(buffer); assert!(m_u64.is_empty()); assert_eq!(m_f64.len(), 1); - assert_eq!(m_f64.get("avail.light.block.confidence"), Some(&90.0)); + assert_eq!(m_f64.get("light.block.confidence"), Some(&90.0)); let buffer = vec![ MetricValue::BlockConfidence(90.0), @@ -420,9 +433,9 @@ mod tests { ]; let (m_u64, m_f64) = flatten_metrics(buffer); assert_eq!(m_u64.len(), 1); - assert_eq!(m_u64.get("avail.light.block.height"), Some(&1)); + assert_eq!(m_u64.get("light.block.height"), Some(&1)); assert_eq!(m_f64.len(), 1); - assert_eq!(m_f64.get("avail.light.block.confidence"), Some(&91.5)); + assert_eq!(m_f64.get("light.block.confidence"), Some(&91.5)); let buffer = vec![ MetricValue::BlockConfidence(90.0), @@ -435,9 +448,9 @@ mod tests { ]; let (m_u64, m_f64) = flatten_metrics(buffer); assert_eq!(m_u64.len(), 1); - assert_eq!(m_u64.get("avail.light.block.height"), Some(&10)); + assert_eq!(m_u64.get("light.block.height"), Some(&10)); assert_eq!(m_f64.len(), 1); - assert_eq!(m_f64.get("avail.light.block.confidence"), Some(&93.75)); + assert_eq!(m_f64.get("light.block.confidence"), Some(&93.75)); let buffer = vec![ MetricValue::DHTConnectedPeers(90), @@ -452,11 +465,11 @@ mod tests { ]; let (m_u64, m_f64) = flatten_metrics(buffer); assert_eq!(m_u64.len(), 1); - assert_eq!(m_u64.get("avail.light.block.height"), Some(&999)); + assert_eq!(m_u64.get("light.block.height"), Some(&999)); assert_eq!(m_f64.len(), 4); - assert_eq!(m_f64.get("avail.light.dht.put_success"), Some(&10.0)); - assert_eq!(m_f64.get("avail.light.dht.fetch_duration"), Some(&1.7)); - assert_eq!(m_f64.get("avail.light.block.confidence"), Some(&98.5)); - assert_eq!(m_f64.get("avail.light.dht.connected_peers"), Some(&85.0)); + assert_eq!(m_f64.get("light.dht.put_success"), Some(&10.0)); + assert_eq!(m_f64.get("light.dht.fetch_duration"), Some(&1.7)); + assert_eq!(m_f64.get("light.block.confidence"), Some(&98.5)); + assert_eq!(m_f64.get("light.dht.connected_peers"), Some(&85.0)); } } diff --git a/core/src/types.rs b/core/src/types.rs index 8b9f2aa2b..37e5929f7 100644 --- a/core/src/types.rs +++ b/core/src/types.rs @@ -358,6 +358,8 @@ pub enum SecretKey { #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(default)] pub struct RuntimeConfig { + /// Name of the project running the client. (default: "avail") + pub project_name: String, #[serde(flatten)] pub api: APIConfig, #[serde(flatten)] @@ -486,6 +488,7 @@ impl From<&RuntimeConfig> for MaintenanceConfig { impl Default for RuntimeConfig { fn default() -> Self { RuntimeConfig { + project_name: "avail".to_string(), api: Default::default(), libp2p: Default::default(), rpc: Default::default(), diff --git a/crawler/src/main.rs b/crawler/src/main.rs index fda3f8c68..b8180526f 100644 --- a/crawler/src/main.rs +++ b/crawler/src/main.rs @@ -81,6 +81,7 @@ async fn run(config: Config, db: DB, shutdown: Controller) -> Result<()> let ot_metrics = Arc::new( otlp::initialize( metric_attributes, + "avail".to_string(), &config.origin, &KademliaMode::Client.into(), config.otel.clone(), @@ -90,6 +91,7 @@ async fn run(config: Config, db: DB, shutdown: Controller) -> Result<()> let (p2p_client, p2p_event_loop, event_receiver) = p2p::init( config.libp2p.clone(), + "avail".to_string(), p2p_keypair, version, &config.genesis_hash, diff --git a/fat/src/main.rs b/fat/src/main.rs index 45957c238..dfc7189be 100644 --- a/fat/src/main.rs +++ b/fat/src/main.rs @@ -81,6 +81,7 @@ async fn run(config: Config, db: DB, shutdown: Controller) -> Result<()> let ot_metrics = Arc::new( telemetry::otlp::initialize( metric_attributes, + "avail".to_string(), &Origin::FatClient, &KademliaMode::Client.into(), config.otel.clone(), @@ -90,6 +91,7 @@ async fn run(config: Config, db: DB, shutdown: Controller) -> Result<()> let (p2p_client, p2p_event_loop, event_receiver) = p2p::init( config.libp2p.clone(), + "avail".to_string(), p2p_keypair, version, &config.genesis_hash,