metrics_example/
main.rs

1// Copyright 2021 Protocol Labs.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21#![doc = include_str!("../README.md")]
22
23use std::error::Error;
24
25use futures::StreamExt;
26use libp2p::{
27    core::Multiaddr,
28    identify, identity,
29    metrics::{Metrics, Recorder},
30    noise, ping,
31    swarm::{NetworkBehaviour, SwarmEvent},
32    tcp, yamux,
33};
34use opentelemetry::{trace::TracerProvider as _, KeyValue};
35use opentelemetry_otlp::SpanExporter;
36use opentelemetry_sdk::{runtime, trace::TracerProvider};
37use prometheus_client::registry::Registry;
38use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
39
40mod http_service;
41
42#[tokio::main]
43async fn main() -> Result<(), Box<dyn Error>> {
44    setup_tracing()?;
45
46    let mut metric_registry = Registry::default();
47
48    let mut swarm = libp2p::SwarmBuilder::with_new_identity()
49        .with_tokio()
50        .with_tcp(
51            tcp::Config::default(),
52            noise::Config::new,
53            yamux::Config::default,
54        )?
55        .with_bandwidth_metrics(&mut metric_registry)
56        .with_behaviour(|key| Behaviour::new(key.public()))?
57        .build();
58
59    swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
60
61    if let Some(addr) = std::env::args().nth(1) {
62        let remote: Multiaddr = addr.parse()?;
63        swarm.dial(remote)?;
64        tracing::info!(address=%addr, "Dialed address")
65    }
66
67    let metrics = Metrics::new(&mut metric_registry);
68    tokio::spawn(http_service::metrics_server(metric_registry));
69
70    loop {
71        match swarm.select_next_some().await {
72            SwarmEvent::NewListenAddr { address, .. } => {
73                tracing::info!(
74                    "Local node is listening on\n {}/p2p/{}",
75                    address,
76                    swarm.local_peer_id()
77                );
78            }
79            SwarmEvent::Behaviour(BehaviourEvent::Ping(ping_event)) => {
80                tracing::info!(?ping_event);
81                metrics.record(&ping_event);
82            }
83            SwarmEvent::Behaviour(BehaviourEvent::Identify(identify_event)) => {
84                tracing::info!(?identify_event);
85                metrics.record(&identify_event);
86            }
87            swarm_event => {
88                tracing::info!(?swarm_event);
89                metrics.record(&swarm_event);
90            }
91        }
92    }
93}
94
95fn setup_tracing() -> Result<(), Box<dyn Error>> {
96    let provider = TracerProvider::builder()
97        .with_batch_exporter(
98            SpanExporter::builder().with_tonic().build()?,
99            runtime::Tokio,
100        )
101        .with_resource(opentelemetry_sdk::Resource::new(vec![KeyValue::new(
102            "service.name",
103            "libp2p",
104        )]))
105        .build();
106    tracing_subscriber::registry()
107        .with(tracing_subscriber::fmt::layer().with_filter(EnvFilter::from_default_env()))
108        .with(
109            tracing_opentelemetry::layer()
110                .with_tracer(provider.tracer("libp2p-subscriber"))
111                .with_filter(EnvFilter::from_default_env()),
112        )
113        .init();
114
115    Ok(())
116}
117
118/// Our network behaviour.
119#[derive(NetworkBehaviour)]
120struct Behaviour {
121    identify: identify::Behaviour,
122    ping: ping::Behaviour,
123}
124
125impl Behaviour {
126    fn new(local_pub_key: identity::PublicKey) -> Self {
127        Self {
128            ping: ping::Behaviour::default(),
129            identify: identify::Behaviour::new(identify::Config::new(
130                "/ipfs/0.1.0".into(),
131                local_pub_key,
132            )),
133        }
134    }
135}