Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/full-node/src/jaeger_service.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! Jaeger integration.
19
//!
20
//! See <https://www.jaegertracing.io/> for an introduction.
21
//!
22
//! The easiest way to try Jaeger is:
23
//!
24
//! - Start a docker container with the all-in-one docker image (see below).
25
//! - Run [`JaegerService`] with [`Config::jaeger_agent`] set to `127.0.0.1:6831`.
26
//! - Open your browser and navigate to <http://localhost:16686> to access the UI.
27
//!
28
//! The all-in-one docker image can be started with:
29
//!
30
//! ```not_rust
31
//! docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 14250:14250 -p 9411:9411 jaegertracing/all-in-one:1
32
//! ```
33
//!
34
35
// TODO: more documentation
36
37
use smol::{future, net::UdpSocket};
38
use smoldot::libp2p::PeerId;
39
use std::{
40
    convert::TryFrom as _, future::Future, io, net::SocketAddr, num::NonZeroU128, pin::Pin,
41
    sync::Arc,
42
};
43
44
/// Configuration for a [`JaegerService`].
45
pub struct Config<'a> {
46
    /// Closure that spawns background tasks.
47
    pub tasks_executor: &'a mut dyn FnMut(Pin<Box<dyn Future<Output = ()> + Send>>),
48
49
    /// Service name to report to the Jaeger agent.
50
    pub service_name: String,
51
52
    /// Address of the Jaeger agent to send traces to. Uses UDP.
53
    ///
54
    /// If this is `None`, the service will still be created but do nothing.
55
    pub jaeger_agent: Option<SocketAddr>,
56
}
57
58
pub struct JaegerService {
59
    traces_in: Arc<mick_jaeger::TracesIn>,
60
61
    /// Notified when the service is destroyed.
62
    shutdown_notify: event_listener::Event,
63
}
64
65
impl JaegerService {
66
21
    pub async fn new(config: Config<'_>) -> Result<Arc<Self>, io::Error> {
_RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService3new
Line
Count
Source
66
21
    pub async fn new(config: Config<'_>) -> Result<Arc<Self>, io::Error> {
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService3new
67
21
        let (traces_in, mut traces_out) = mick_jaeger::init(mick_jaeger::Config {
68
21
            service_name: config.service_name,
69
21
        });
70
21
71
21
        let shutdown_notify = event_listener::Event::new();
72
73
21
        if let Some(
jaeger_agent0
) = config.jaeger_agent {
74
0
            let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
75
0
            let mut on_shutdown = shutdown_notify.listen();
76
0
77
0
            // Spawn a background task that pulls span information and sends them on the network.
78
0
            (config.tasks_executor)(Box::pin(async move {
79
                loop {
80
0
                    let Some(buf) = future::or(
81
0
                        async {
82
0
                            (&mut on_shutdown).await;
83
0
                            None
84
0
                        },
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new000CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new000Ba_
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new000CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new000CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCNCNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new000Ba_
85
0
                        async { Some(traces_out.next().await) },
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new00s_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new00s_0Ba_
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new00s_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new00s_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCNCNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB8_13JaegerService3new00s_0Ba_
86
0
                    )
87
0
                    .await
88
                    else {
89
0
                        break;
90
                    };
91
92
                    // UDP sending errors happen only either if the API is misused (in which case
93
                    // panicking is desirable) or in case of missing priviledge, in which case a
94
                    // panic is preferable in order to inform the user.
95
0
                    udp_socket.send_to(&buf, jaeger_agent).await.unwrap();
96
                }
97
0
            }));
Unexecuted instantiation: _RNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB6_13JaegerService3new00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB6_13JaegerService3new00B8_
Unexecuted instantiation: _RNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB6_13JaegerService3new00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB6_13JaegerService3new00CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB6_13JaegerService3new00B8_
98
21
        }
99
100
21
        Ok(Arc::new(JaegerService {
101
21
            traces_in,
102
21
            shutdown_notify,
103
21
        }))
104
21
    }
_RNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB4_13JaegerService3new0CsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
66
2
    pub async fn new(config: Config<'_>) -> Result<Arc<Self>, io::Error> {
67
2
        let (traces_in, mut traces_out) = mick_jaeger::init(mick_jaeger::Config {
68
2
            service_name: config.service_name,
69
2
        });
70
2
71
2
        let shutdown_notify = event_listener::Event::new();
72
73
2
        if let Some(
jaeger_agent0
) = config.jaeger_agent {
74
0
            let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
75
0
            let mut on_shutdown = shutdown_notify.listen();
76
0
77
0
            // Spawn a background task that pulls span information and sends them on the network.
78
0
            (config.tasks_executor)(Box::pin(async move {
79
                loop {
80
                    let Some(buf) = future::or(
81
                        async {
82
                            (&mut on_shutdown).await;
83
                            None
84
                        },
85
                        async { Some(traces_out.next().await) },
86
                    )
87
                    .await
88
                    else {
89
                        break;
90
                    };
91
92
                    // UDP sending errors happen only either if the API is misused (in which case
93
                    // panicking is desirable) or in case of missing priviledge, in which case a
94
                    // panic is preferable in order to inform the user.
95
                    udp_socket.send_to(&buf, jaeger_agent).await.unwrap();
96
                }
97
0
            }));
98
2
        }
99
100
2
        Ok(Arc::new(JaegerService {
101
2
            traces_in,
102
2
            shutdown_notify,
103
2
        }))
104
2
    }
Unexecuted instantiation: _RNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB4_13JaegerService3new0B6_
Unexecuted instantiation: _RNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB4_13JaegerService3new0CscDgN54JpMGG_6author
_RNCNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB4_13JaegerService3new0CsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
66
19
    pub async fn new(config: Config<'_>) -> Result<Arc<Self>, io::Error> {
67
19
        let (traces_in, mut traces_out) = mick_jaeger::init(mick_jaeger::Config {
68
19
            service_name: config.service_name,
69
19
        });
70
19
71
19
        let shutdown_notify = event_listener::Event::new();
72
73
19
        if let Some(
jaeger_agent0
) = config.jaeger_agent {
74
0
            let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
75
0
            let mut on_shutdown = shutdown_notify.listen();
76
0
77
0
            // Spawn a background task that pulls span information and sends them on the network.
78
0
            (config.tasks_executor)(Box::pin(async move {
79
                loop {
80
                    let Some(buf) = future::or(
81
                        async {
82
                            (&mut on_shutdown).await;
83
                            None
84
                        },
85
                        async { Some(traces_out.next().await) },
86
                    )
87
                    .await
88
                    else {
89
                        break;
90
                    };
91
92
                    // UDP sending errors happen only either if the API is misused (in which case
93
                    // panicking is desirable) or in case of missing priviledge, in which case a
94
                    // panic is preferable in order to inform the user.
95
                    udp_socket.send_to(&buf, jaeger_agent).await.unwrap();
96
                }
97
0
            }));
98
19
        }
99
100
19
        Ok(Arc::new(JaegerService {
101
19
            traces_in,
102
19
            shutdown_notify,
103
19
        }))
104
19
    }
Unexecuted instantiation: _RNCNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB4_13JaegerService3new0B6_
105
106
0
    pub fn block_announce_receive_span(
107
0
        &self,
108
0
        local_peer_id: &PeerId,
109
0
        remote_peer_id: &PeerId,
110
0
        block_number: u64,
111
0
        block_hash: &[u8; 32],
112
0
    ) -> mick_jaeger::Span {
113
0
        let mut span =
114
0
            self.net_connection_span(local_peer_id, remote_peer_id, "block-announce-received");
115
0
        if let Ok(block_number) = i64::try_from(block_number) {
116
0
            span.add_int_tag("number", block_number);
117
0
        }
118
0
        span.add_string_tag("hash", &hex::encode(block_hash));
119
0
        span
120
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService27block_announce_receive_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService27block_announce_receive_span
121
122
0
    pub fn block_announce_process_span(&self, block_hash: &[u8; 32]) -> mick_jaeger::Span {
123
0
        self.block_span(block_hash, "block-announce-process")
124
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService27block_announce_process_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService27block_announce_process_span
125
126
0
    pub fn block_authorship_span(
127
0
        &self,
128
0
        block_hash: &[u8; 32],
129
0
        start_time: mick_jaeger::StartTime,
130
0
    ) -> mick_jaeger::Span {
131
0
        self.block_span(block_hash, "author")
132
0
            .with_start_time_override(start_time)
133
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService21block_authorship_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService21block_authorship_span
134
135
0
    pub fn block_verify_span(&self, block_hash: &[u8; 32]) -> mick_jaeger::Span {
136
0
        self.block_span(block_hash, "block-verify")
137
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService17block_verify_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService17block_verify_span
138
139
0
    pub fn block_import_queue_span(&self, block_hash: &[u8; 32]) -> mick_jaeger::Span {
140
0
        self.block_span(block_hash, "block-import-queue")
141
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService23block_import_queue_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService23block_import_queue_span
142
143
    // TODO: better return type
144
0
    pub fn incoming_block_request_span(
145
0
        &self,
146
0
        local_peer_id: &PeerId,
147
0
        remote_peer_id: &PeerId,
148
0
        num_requested_blocks: u32,
149
0
        block_hash: Option<&[u8; 32]>,
150
0
    ) -> [Option<mick_jaeger::Span>; 2] {
151
0
        let mut span1 =
152
0
            self.net_connection_span(local_peer_id, remote_peer_id, "incoming-blocks-request");
153
0
        span1.add_int_tag("num-blocks", num_requested_blocks.into());
154
155
0
        let span2 = if let Some(block_hash) = block_hash {
156
0
            let mut span = self.block_span(block_hash, "incoming-blocks-request");
157
0
            let hex = hex::encode(block_hash);
158
0
            span.add_string_tag("hash", &hex);
159
0
            span1.add_string_tag("hash", &hex);
160
0
            Some(span)
161
        } else {
162
0
            None
163
        };
164
165
0
        [Some(span1), span2]
166
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService27incoming_block_request_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService27incoming_block_request_span
167
168
    // TODO: unused
169
0
    pub fn _outgoing_block_request_span(
170
0
        &self,
171
0
        local_peer_id: &PeerId,
172
0
        remote_peer_id: &PeerId,
173
0
        num_requested_blocks: u32,
174
0
        block_hash: Option<&[u8; 32]>,
175
0
    ) -> [Option<mick_jaeger::Span>; 2] {
176
0
        let mut span1 =
177
0
            self.net_connection_span(local_peer_id, remote_peer_id, "outgoing-blocks-request");
178
0
        span1.add_int_tag("num-blocks", num_requested_blocks.into());
179
180
0
        let span2 = if let Some(block_hash) = block_hash {
181
0
            let mut span = self.block_span(block_hash, "outgoing-blocks-request");
182
0
            let hex = hex::encode(block_hash);
183
0
            span.add_string_tag("hash", &hex);
184
0
            span1.add_string_tag("hash", &hex);
185
0
            Some(span)
186
        } else {
187
0
            None
188
        };
189
190
0
        [Some(span1), span2]
191
0
    }
Unexecuted instantiation: _RNvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService28__outgoing_block_request_span
Unexecuted instantiation: _RNvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB2_13JaegerService28__outgoing_block_request_span
192
193
    /// Creates a new `Span` that refers to an event about a given block.
194
    ///
195
    /// This function is private so that only the code in the `jaeger_service` module decides
196
    /// which names and labels to apply to spans. This makes it possible to easily ensure some
197
    /// consistency in these names and labels.
198
0
    fn block_span(
199
0
        &self,
200
0
        block_hash: &[u8; 32],
201
0
        operation_name: impl Into<String>,
202
0
    ) -> mick_jaeger::Span {
203
0
        let trace_id = NonZeroU128::new(u128::from_be_bytes(
204
0
            <[u8; 16]>::try_from(&block_hash[16..]).unwrap(),
205
0
        ))
206
0
        .unwrap_or_else(|| NonZeroU128::new(1u128).unwrap());
Unexecuted instantiation: _RNCINvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB5_13JaegerService10block_spanReE0B7_
Unexecuted instantiation: _RNCINvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB5_13JaegerService10block_spanpE0B7_
207
0
        self.traces_in.span(trace_id, operation_name)
208
0
    }
Unexecuted instantiation: _RINvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB3_13JaegerService10block_spanReEB5_
Unexecuted instantiation: _RINvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB3_13JaegerService10block_spanpEB5_
209
210
    /// Creates a new `Span` that refers to a specific network connection between two nodes.
211
    ///
212
    /// This function is private so that only the code in the `jaeger_service` module decides
213
    /// which names and labels to apply to spans. This makes it possible to easily ensure some
214
    /// consistency in these names and labels.
215
0
    fn net_connection_span(
216
0
        &self,
217
0
        local_peer_id: &PeerId,
218
0
        remote_peer_id: &PeerId,
219
0
        operation_name: impl Into<String>,
220
0
    ) -> mick_jaeger::Span {
221
0
        let local_peer_id = local_peer_id.as_bytes();
222
0
        let remote_peer_id = remote_peer_id.as_bytes();
223
0
224
0
        let mut buf = [0; 16];
225
0
        if local_peer_id < remote_peer_id {
226
0
            buf[..8].copy_from_slice(&local_peer_id[local_peer_id.len() - 8..]);
227
0
            buf[8..].copy_from_slice(&remote_peer_id[remote_peer_id.len() - 8..]);
228
0
        } else {
229
0
            buf[..8].copy_from_slice(&remote_peer_id[remote_peer_id.len() - 8..]);
230
0
            buf[8..].copy_from_slice(&local_peer_id[local_peer_id.len() - 8..]);
231
0
        };
232
233
0
        let trace_id = NonZeroU128::new(u128::from_be_bytes(buf)).unwrap();
234
0
        self.traces_in.span(trace_id, operation_name)
235
0
    }
Unexecuted instantiation: _RINvMNtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB3_13JaegerService19net_connection_spanReEB5_
Unexecuted instantiation: _RINvMNtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB3_13JaegerService19net_connection_spanpEB5_
236
}
237
238
impl Drop for JaegerService {
239
0
    fn drop(&mut self) {
240
0
        self.shutdown_notify.notify(usize::MAX);
241
0
    }
Unexecuted instantiation: _RNvXs_NtCsiUjFBJteJ7x_17smoldot_full_node14jaeger_serviceNtB4_13JaegerServiceNtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4drop
Unexecuted instantiation: _RNvXs_NtCshBwayKnNXDT_17smoldot_full_node14jaeger_serviceNtB4_13JaegerServiceNtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4drop
242
}