1use codec::Encode;
87use polkadot_node_primitives::PoV;
88use polkadot_primitives::{
89 BlakeTwo256, CandidateHash, ChunkIndex, Hash, HashT, Id as ParaId, ValidatorIndex,
90};
91use sc_network_types::PeerId;
92
93use std::{fmt, sync::Arc};
94
95use super::INSTANCE;
96
97#[derive(Debug)]
106pub struct PerLeafSpan {
107 leaf_span: Arc<Span>,
108 span: Span,
109}
110
111impl PerLeafSpan {
112 pub fn new(leaf_span: Arc<Span>, name: &'static str) -> Self {
118 let span = leaf_span.child(name);
119
120 Self { span, leaf_span }
121 }
122
123 pub fn leaf_span(&self) -> &Arc<Span> {
125 &self.leaf_span
126 }
127}
128
129impl std::ops::Deref for PerLeafSpan {
131 type Target = Span;
132
133 fn deref(&self) -> &Span {
134 &self.span
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144#[repr(u8)]
145#[non_exhaustive]
146pub enum Stage {
147 CandidateBacking = 2,
148 StatementDistribution = 3,
149 PoVDistribution = 4,
150 AvailabilityDistribution = 5,
151 AvailabilityRecovery = 6,
152 BitfieldDistribution = 7,
153 ApprovalChecking = 8,
154 ApprovalDistribution = 9,
155 }
161
162pub enum Span {
166 Enabled(mick_jaeger::Span),
168 Disabled,
170}
171
172pub(crate) type TraceIdentifier = u128;
174
175#[inline]
178pub fn hash_to_trace_identifier(hash: Hash) -> TraceIdentifier {
179 let mut buf = [0u8; 16];
180 buf.copy_from_slice(&hash.as_ref()[0..16]);
181 u128::from_be_bytes(buf) as TraceIdentifier
186}
187
188pub trait LazyIdent {
190 fn eval(&self) -> TraceIdentifier;
193
194 fn extra_tags(&self, _span: &mut Span) {}
197}
198
199impl<'a> LazyIdent for &'a [u8] {
200 fn eval(&self) -> TraceIdentifier {
201 hash_to_trace_identifier(BlakeTwo256::hash_of(self))
202 }
203}
204
205impl LazyIdent for &PoV {
206 fn eval(&self) -> TraceIdentifier {
207 hash_to_trace_identifier(self.hash())
208 }
209
210 fn extra_tags(&self, span: &mut Span) {
211 span.add_pov(self)
212 }
213}
214
215impl LazyIdent for Hash {
216 fn eval(&self) -> TraceIdentifier {
217 hash_to_trace_identifier(*self)
218 }
219
220 fn extra_tags(&self, span: &mut Span) {
221 span.add_string_fmt_debug_tag("relay-parent", self);
222 }
223}
224
225impl LazyIdent for &Hash {
226 fn eval(&self) -> TraceIdentifier {
227 hash_to_trace_identifier(**self)
228 }
229
230 fn extra_tags(&self, span: &mut Span) {
231 span.add_string_fmt_debug_tag("relay-parent", self);
232 }
233}
234
235impl LazyIdent for CandidateHash {
236 fn eval(&self) -> TraceIdentifier {
237 hash_to_trace_identifier(self.0)
238 }
239
240 fn extra_tags(&self, span: &mut Span) {
241 span.add_string_fmt_debug_tag("candidate-hash", &self.0);
242 span.add_string_tag("traceID", self.eval().to_string());
248 }
249}
250
251impl Span {
252 pub fn new<I: LazyIdent>(identifier: I, span_name: &'static str) -> Span {
258 let mut span = INSTANCE
259 .read_recursive()
260 .span(|| <I as LazyIdent>::eval(&identifier), span_name)
261 .into();
262 <I as LazyIdent>::extra_tags(&identifier, &mut span);
263 span
264 }
265
266 pub fn from_encodable<I: Encode>(identifier: I, span_name: &'static str) -> Span {
269 INSTANCE
270 .read_recursive()
271 .span(
272 move || {
273 let bytes = identifier.encode();
274 LazyIdent::eval(&bytes.as_slice())
275 },
276 span_name,
277 )
278 .into()
279 }
280
281 pub fn child(&self, name: &str) -> Self {
283 match self {
284 Self::Enabled(inner) => Self::Enabled(inner.child(name)),
285 Self::Disabled => Self::Disabled,
286 }
287 }
288
289 #[inline(always)]
291 pub fn with_trace_id(mut self, candidate_hash: CandidateHash) -> Self {
292 self.add_string_tag("traceID", hash_to_trace_identifier(candidate_hash.0));
293 self
294 }
295
296 #[inline(always)]
297 pub fn with_string_tag<V: ToString>(mut self, tag: &'static str, val: V) -> Self {
298 self.add_string_tag::<V>(tag, val);
299 self
300 }
301
302 #[inline(always)]
304 pub fn with_peer_id(self, peer: &PeerId) -> Self {
305 self.with_string_tag("peer-id", &peer.to_base58())
306 }
307
308 #[inline(always)]
310 pub fn with_optional_peer_id(self, peer: Option<&PeerId>) -> Self {
311 if let Some(peer) = peer {
312 self.with_peer_id(peer)
313 } else {
314 self
315 }
316 }
317
318 #[inline(always)]
320 pub fn with_candidate(self, candidate_hash: CandidateHash) -> Self {
321 self.with_string_fmt_debug_tag("candidate-hash", &candidate_hash.0)
322 }
323
324 #[inline(always)]
326 pub fn with_para_id(self, para_id: ParaId) -> Self {
327 self.with_int_tag("para-id", u32::from(para_id) as i64)
328 }
329
330 #[inline(always)]
333 pub fn with_stage(self, stage: Stage) -> Self {
334 self.with_string_tag("candidate-stage", stage as u8)
335 }
336
337 #[inline(always)]
338 pub fn with_validator_index(self, validator: ValidatorIndex) -> Self {
339 self.with_string_tag("validator-index", &validator.0)
340 }
341
342 #[inline(always)]
343 pub fn with_chunk_index(self, chunk_index: ChunkIndex) -> Self {
344 self.with_string_tag("chunk-index", &chunk_index.0)
345 }
346
347 #[inline(always)]
348 pub fn with_relay_parent(self, relay_parent: Hash) -> Self {
349 self.with_string_fmt_debug_tag("relay-parent", relay_parent)
350 }
351
352 #[inline(always)]
353 pub fn with_claimed_validator_index(self, claimed_validator_index: ValidatorIndex) -> Self {
354 self.with_string_tag("claimed-validator", &claimed_validator_index.0)
355 }
356
357 #[inline(always)]
358 pub fn with_pov(mut self, pov: &PoV) -> Self {
359 self.add_pov(pov);
360 self
361 }
362
363 #[inline(always)]
367 pub fn with_int_tag(mut self, tag: &'static str, i: i64) -> Self {
368 self.add_int_tag(tag, i);
369 self
370 }
371
372 #[inline(always)]
373 pub fn with_uint_tag(mut self, tag: &'static str, u: u64) -> Self {
374 self.add_uint_tag(tag, u);
375 self
376 }
377
378 #[inline(always)]
379 pub fn with_string_fmt_debug_tag<V: fmt::Debug>(mut self, tag: &'static str, val: V) -> Self {
380 self.add_string_tag(tag, format!("{:?}", val));
381 self
382 }
383
384 #[inline(always)]
386 pub fn add_follows_from(&mut self, other: &Self) {
387 match (self, other) {
388 (Self::Enabled(ref mut inner), Self::Enabled(ref other_inner)) =>
389 inner.add_follows_from(&other_inner),
390 _ => {},
391 }
392 }
393
394 #[inline(always)]
396 pub fn add_pov(&mut self, pov: &PoV) {
397 if self.is_enabled() {
398 self.add_string_fmt_debug_tag("pov", pov.hash());
400 }
401 }
402
403 #[inline(always)]
404 pub fn add_para_id(&mut self, para_id: ParaId) {
405 self.add_int_tag("para-id", u32::from(para_id) as i64);
406 }
407
408 pub fn add_string_tag<V: ToString>(&mut self, tag: &'static str, val: V) {
410 match self {
411 Self::Enabled(ref mut inner) => inner.add_string_tag(tag, val.to_string().as_str()),
412 Self::Disabled => {},
413 }
414 }
415
416 pub fn add_string_fmt_debug_tag<V: fmt::Debug>(&mut self, tag: &'static str, val: V) {
418 match self {
419 Self::Enabled(ref mut inner) =>
420 inner.add_string_tag(tag, format!("{:?}", val).as_str()),
421 Self::Disabled => {},
422 }
423 }
424
425 pub fn add_int_tag(&mut self, tag: &'static str, value: i64) {
426 match self {
427 Self::Enabled(ref mut inner) => inner.add_int_tag(tag, value),
428 Self::Disabled => {},
429 }
430 }
431
432 pub fn add_uint_tag(&mut self, tag: &'static str, value: u64) {
433 match self {
434 Self::Enabled(ref mut inner) => inner.add_int_tag(tag, value as i64),
435 Self::Disabled => {},
436 }
437 }
438
439 pub const fn is_enabled(&self) -> bool {
442 match self {
443 Span::Enabled(_) => true,
444 _ => false,
445 }
446 }
447
448 pub fn trace_id(&self) -> Option<TraceIdentifier> {
450 match self {
451 Span::Enabled(inner) => Some(inner.trace_id().get()),
452 _ => None,
453 }
454 }
455}
456
457impl std::fmt::Debug for Span {
458 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
459 write!(f, "<jaeger span>")
460 }
461}
462
463impl From<Option<mick_jaeger::Span>> for Span {
464 fn from(src: Option<mick_jaeger::Span>) -> Self {
465 if let Some(span) = src {
466 Self::Enabled(span)
467 } else {
468 Self::Disabled
469 }
470 }
471}
472
473impl From<mick_jaeger::Span> for Span {
474 fn from(src: mick_jaeger::Span) -> Self {
475 Self::Enabled(src)
476 }
477}
478
479#[cfg(test)]
480mod tests {
481 use super::*;
482 use crate::Jaeger;
483
484 const RAW: [u8; 32] = [
486 0xFF, 0xAA, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x78, 0x89, 0x9A, 0xAB, 0xBC, 0xCD, 0xDE,
487 0xEF, 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
488 0x0E, 0x0F,
489 ];
490
491 #[test]
492 fn hash_derived_identifier_is_leading_16bytes() {
493 let candidate_hash = dbg!(Hash::from(&RAW));
494 let trace_id = dbg!(hash_to_trace_identifier(candidate_hash));
495 for (idx, (a, b)) in candidate_hash
496 .as_bytes()
497 .iter()
498 .take(16)
499 .zip(trace_id.to_be_bytes().iter())
500 .enumerate()
501 {
502 assert_eq!(*a, *b, "Index [{}] does not match: {} != {}", idx, a, b);
503 }
504 }
505
506 #[test]
507 fn extra_tags_do_not_change_trace_id() {
508 Jaeger::test_setup();
509 let candidate_hash = dbg!(Hash::from(&RAW));
510 let trace_id = hash_to_trace_identifier(candidate_hash);
511
512 let span = Span::new(candidate_hash, "foo");
513
514 assert_eq!(span.trace_id(), Some(trace_id));
515
516 let span = span.with_int_tag("tag", 7i64);
517
518 assert_eq!(span.trace_id(), Some(trace_id));
519 }
520}