/__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 | | } |