diff --git a/Cargo.lock b/Cargo.lock index f9e3e92ab..88d2d70b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,12 +889,14 @@ dependencies = [ [[package]] name = "avail-light-bootstrap" -version = "0.4.2" +version = "0.5.0" dependencies = [ "anyhow", "async-std", "async-trait", + "avail-light-core", "clap", + "color-eyre", "confy 0.5.1", "hex", "libp2p", diff --git a/bootstrap/CHANGELOG.md b/bootstrap/CHANGELOG.md index 22d6802a9..a27c23f2a 100644 --- a/bootstrap/CHANGELOG.md +++ b/bootstrap/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.5.0 + +- Use telemetry from the avail-light-core 1.2.0 + ## [0.4.2](https://github.com/availproject/avail-light/releases/tag/avail-light-bootstrap-v0.4.2) - 2024-12-20 - Temporary remove WebRTC support to reduce memory usage diff --git a/bootstrap/Cargo.toml b/bootstrap/Cargo.toml index 1195d661d..8c51eb3ae 100644 --- a/bootstrap/Cargo.toml +++ b/bootstrap/Cargo.toml @@ -1,15 +1,18 @@ [package] name = "avail-light-bootstrap" -version = "0.4.2" +version = "0.5.0" build = "../build.rs" edition = "2021" description = "Avail network Bootstrap Node for p2p Light Client" [dependencies] +avail-light-core = { workspace = true } + anyhow = { workspace = true } async-std = { workspace = true } async-trait = { workspace = true } clap = { workspace = true } +color-eyre = { workspace = true } confy = { workspace = true } hex = { workspace = true } libp2p = { workspace = true } diff --git a/bootstrap/src/main.rs b/bootstrap/src/main.rs index dc3131e7c..a6eedb4bb 100644 --- a/bootstrap/src/main.rs +++ b/bootstrap/src/main.rs @@ -1,10 +1,11 @@ #![doc = include_str!("../README.md")] -use crate::{ - telemetry::{MetricValue, Metrics}, - types::{network_name, LibP2PConfig}, -}; +use crate::types::{network_name, LibP2PConfig}; use anyhow::{Context, Result}; +use avail_light_core::{ + telemetry::{self, MetricCounter, MetricValue}, + types::{Origin, ProjectName}, +}; use clap::Parser; use libp2p::{multiaddr::Protocol, Multiaddr}; use std::{net::Ipv4Addr, time::Duration}; @@ -18,7 +19,6 @@ use types::RuntimeConfig; mod p2p; mod server; -mod telemetry; mod types; const CLIENT_ROLE: &str = "bootnode"; @@ -88,14 +88,22 @@ async fn run() -> Result<()> { tokio::spawn(server::run((&cfg).into(), network_client.clone())); - let ot_metrics = telemetry::otlp::initialize( - cfg.ot_collector_endpoint, - peer_id, - CLIENT_ROLE.into(), - cfg.origin, - network_name(&cfg.genesis_hash), + let resource_attributes = vec![ + ("version", version.to_string()), + ("role", CLIENT_ROLE.to_string()), + ("peerID", peer_id.to_string()), + ("origin", cfg.origin.clone()), + ("network", network_name(&cfg.genesis_hash)), + ]; + + let mut ot_metrics = telemetry::otlp::initialize( + ProjectName::new("avail".to_string()), + &Origin::Other(cfg.origin), + cfg.otel, + resource_attributes, ) - .context("Cannot initialize OpenTelemetry service.")?; + .map_err(anyhow::Error::msg) + .context("Unable to initialize OpenTelemetry service")?; // Spawn the network task let loop_handle = tokio::spawn(network_event_loop.run()); @@ -109,20 +117,11 @@ async fn run() -> Result<()> { loop { interval.tick().await; // try and read current multiaddress - if let Ok(Some(addr)) = m_network_client.get_multiaddress().await { - // set Multiaddress - _ = ot_metrics.set_multiaddress(addr.to_string()).await; - } if let Ok(counted_peers) = m_network_client.count_dht_entries().await { debug!("Number of peers in the routing table: {}", counted_peers); - if let Err(err) = ot_metrics - .record(MetricValue::KadRoutingPeerNum(counted_peers)) - .await - { - error!("Error recording network stats metric: {err}"); - } + ot_metrics.record(MetricValue::DHTConnectedPeers(counted_peers)); }; - _ = ot_metrics.record(MetricValue::HealthCheck()).await; + ot_metrics.count(MetricCounter::Up); } }); diff --git a/bootstrap/src/p2p/client.rs b/bootstrap/src/p2p/client.rs index a0c2b6b7a..7712d9d0a 100644 --- a/bootstrap/src/p2p/client.rs +++ b/bootstrap/src/p2p/client.rs @@ -84,15 +84,6 @@ impl Client { response_receiver.await.context("Sender not to be dropped.") } - pub async fn get_multiaddress(&self) -> Result> { - let (response_sender, response_receiver) = oneshot::channel(); - self.command_sender - .send(Command::GetMultiaddress { response_sender }) - .await - .context("Command receiver not to be dropped.")?; - response_receiver.await.context("Sender not to be dropped.") - } - pub async fn get_local_peer_info(&self) -> Result { let (response_sender, response_receiver) = oneshot::channel(); self.command_sender @@ -122,9 +113,6 @@ pub enum Command { CountDHTPeers { response_sender: oneshot::Sender, }, - GetMultiaddress { - response_sender: oneshot::Sender>, - }, GetLocalPeerInfo { response_sender: oneshot::Sender, }, diff --git a/bootstrap/src/p2p/event_loop.rs b/bootstrap/src/p2p/event_loop.rs index 90f44c7cf..a32e9119a 100644 --- a/bootstrap/src/p2p/event_loop.rs +++ b/bootstrap/src/p2p/event_loop.rs @@ -259,10 +259,6 @@ impl EventLoop { } _ = response_sender.send(total_peers); }, - Command::GetMultiaddress { response_sender } => { - let last_address = self.swarm.external_addresses().last(); - _ = response_sender.send(last_address.cloned()); - }, Command::GetLocalPeerInfo { response_sender } => { let local_listeners: Vec = self.swarm.listeners().map(ToString::to_string).collect(); diff --git a/bootstrap/src/telemetry/mod.rs b/bootstrap/src/telemetry/mod.rs deleted file mode 100644 index 913a49d5e..000000000 --- a/bootstrap/src/telemetry/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -use anyhow::Result; -use async_trait::async_trait; - -pub mod otlp; - -pub enum MetricValue { - KadRoutingPeerNum(usize), - HealthCheck(), -} - -#[async_trait] -pub trait Metrics { - async fn record(&self, value: MetricValue) -> Result<()>; - async fn set_multiaddress(&self, multiaddrs: String); -} diff --git a/bootstrap/src/telemetry/otlp.rs b/bootstrap/src/telemetry/otlp.rs deleted file mode 100644 index 5945374ba..000000000 --- a/bootstrap/src/telemetry/otlp.rs +++ /dev/null @@ -1,108 +0,0 @@ -use anyhow::{Error, Ok, Result}; -use async_trait::async_trait; -use opentelemetry::{global, metrics::Meter, KeyValue}; -use opentelemetry_otlp::{MetricExporter, Protocol, WithExportConfig}; -use opentelemetry_sdk::{ - metrics::{PeriodicReader, SdkMeterProvider}, - runtime::Tokio, - Resource, -}; -use std::time::Duration; -use tokio::sync::RwLock; - -pub struct Metrics { - meter: Meter, - peer_id: String, - multiaddress: RwLock, - role: String, - origin: String, - network: String, -} - -impl Metrics { - async fn attributes(&self) -> [KeyValue; 6] { - [ - KeyValue::new("version", clap::crate_version!()), - KeyValue::new("role", self.role.clone()), - KeyValue::new("peerID", self.peer_id.clone()), - KeyValue::new("multiaddress", self.multiaddress.read().await.clone()), - KeyValue::new("origin", self.origin.clone()), - KeyValue::new("network", self.network.clone()), - ] - } - - async fn record_u64(&self, name: &'static str, value: u64) -> Result<()> { - let attributes = self.attributes().await; - self.meter - .u64_observable_gauge(name) - .with_callback(move |observer| { - observer.observe(value, &attributes); - }) - .build(); - Ok(()) - } - - async fn set_multiaddress(&self, multiaddr: String) { - let mut m = self.multiaddress.write().await; - *m = multiaddr; - } -} - -#[async_trait] -impl super::Metrics for Metrics { - async fn record(&self, value: super::MetricValue) -> Result<()> { - match value { - super::MetricValue::KadRoutingPeerNum(num) => { - self.record_u64("kad_routing_peer_num", num as u64).await?; - }, - super::MetricValue::HealthCheck() => { - self.record_u64("up", 1).await?; - }, - } - Ok(()) - } - - async fn set_multiaddress(&self, multiaddr: String) { - self.set_multiaddress(multiaddr).await; - } -} - -pub fn initialize( - endpoint: String, - peer_id: String, - role: String, - origin: String, - network: String, -) -> Result { - let exporter = MetricExporter::builder() - .with_tonic() - .with_endpoint(&endpoint) - .with_protocol(Protocol::Grpc) - .with_timeout(Duration::from_secs(30)) - .build()?; - - let reader = PeriodicReader::builder(exporter, Tokio) - .with_interval(Duration::from_secs(30)) - .with_timeout(Duration::from_secs(30)) - .build(); - - let provider = SdkMeterProvider::builder() - .with_reader(reader) - .with_resource(Resource::new(vec![KeyValue::new( - "service.name", - "bootstrap".to_string(), - )])) - .build(); - - global::set_meter_provider(provider); - let meter = global::meter("avail_light_bootstrap"); - - Ok(Metrics { - meter, - peer_id, - multiaddress: RwLock::new("".to_string()), - role, - origin, - network, - }) -} diff --git a/bootstrap/src/types.rs b/bootstrap/src/types.rs index 1dfb4ed8c..f1edd6757 100644 --- a/bootstrap/src/types.rs +++ b/bootstrap/src/types.rs @@ -1,4 +1,5 @@ use anyhow::{anyhow, Context, Error}; +use avail_light_core::telemetry::otlp::OtelConfig; use libp2p::{Multiaddr, PeerId, StreamProtocol}; use semver::Version; use serde::{Deserialize, Serialize}; @@ -99,8 +100,8 @@ pub struct RuntimeConfig { pub bootstraps: Vec, /// Defines a period of time in which periodic bootstraps will be repeated. (default: 300s) pub bootstrap_period: u64, - /// OpenTelemetry Collector endpoint (default: http://127.0.0.1:4317) - pub ot_collector_endpoint: String, + #[serde(flatten)] + pub otel: OtelConfig, /// Defines a period of time in which periodic metric network dump events will be repeated. (default: 15s) pub metrics_network_dump_interval: u64, /// Secret key used to generate keypair. Can be either set to `seed` or to `key`. (default: seed="1") @@ -213,7 +214,7 @@ impl Default for RuntimeConfig { kad_query_timeout: 60, bootstraps: vec![], bootstrap_period: 300, - ot_collector_endpoint: "http://127.0.0.1:4317".to_string(), + otel: Default::default(), metrics_network_dump_interval: 15, origin: "external".to_string(), genesis_hash: "DEV".to_owned(),