Skip to main content

soil_client/tracing/logging/layers/
prefix_layer.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7use tracing::{span::Attributes, Id, Subscriber};
8use tracing_subscriber::{layer::Context, registry::LookupSpan, Layer};
9
10/// Span name used for the logging prefix. See macro `sc_tracing::logging::prefix_logs_with!`
11pub const PREFIX_LOG_SPAN: &str = "substrate-log-prefix";
12
13/// A `Layer` that captures the prefix span ([`PREFIX_LOG_SPAN`]) which is then used by
14/// [`crate::logging::EventFormat`] to prefix the log lines by customizable string.
15///
16/// See the macro `soil_cli::prefix_logs_with!` for more details.
17pub struct PrefixLayer;
18
19impl<S> Layer<S> for PrefixLayer
20where
21	S: Subscriber + for<'a> LookupSpan<'a>,
22{
23	fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
24		let span = match ctx.span(id) {
25			Some(span) => span,
26			None => {
27				// this shouldn't happen!
28				debug_assert!(
29					false,
30					"newly created span with ID {:?} did not exist in the registry; this is a bug!",
31					id
32				);
33				return;
34			},
35		};
36
37		if span.name() != PREFIX_LOG_SPAN {
38			return;
39		}
40
41		let mut extensions = span.extensions_mut();
42
43		if extensions.get_mut::<Prefix>().is_none() {
44			let mut s = String::new();
45			let mut v = PrefixVisitor(&mut s);
46			attrs.record(&mut v);
47
48			if !s.is_empty() {
49				let fmt_fields = Prefix(s);
50				extensions.insert(fmt_fields);
51			}
52		}
53	}
54}
55
56struct PrefixVisitor<'a, W: std::fmt::Write>(&'a mut W);
57
58macro_rules! write_node_name {
59	($method:ident, $type:ty, $format:expr) => {
60		fn $method(&mut self, field: &tracing::field::Field, value: $type) {
61			if field.name() == "name" {
62				let _ = write!(self.0, $format, value);
63			}
64		}
65	};
66}
67
68impl<'a, W: std::fmt::Write> tracing::field::Visit for PrefixVisitor<'a, W> {
69	write_node_name!(record_debug, &dyn std::fmt::Debug, "[{:?}] ");
70	write_node_name!(record_str, &str, "[{}] ");
71	write_node_name!(record_i64, i64, "[{}] ");
72	write_node_name!(record_u64, u64, "[{}] ");
73	write_node_name!(record_bool, bool, "[{}] ");
74}
75
76#[derive(Debug)]
77pub(crate) struct Prefix(String);
78
79impl Prefix {
80	pub(crate) fn as_str(&self) -> &str {
81		self.0.as_str()
82	}
83}