1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! Substrate tracing primitives and macros.
19
//!
20
//! To trace functions or individual code in Substrate, this crate provides [`within_span`]
21
//! and [`enter_span`]. See the individual docs for how to use these macros.
22
//!
23
//! Note that to allow traces from wasm execution environment there are
24
//! 2 reserved identifiers for tracing `Field` recording, stored in the consts:
25
//! `WASM_TARGET_KEY` and `WASM_NAME_KEY` - if you choose to record fields, you
26
//! must ensure that your identifiers do not clash with either of these.
27
//!
28
//! Additionally, we have a const: `WASM_TRACE_IDENTIFIER`, which holds a span name used
29
//! to signal that the 'actual' span name and target should be retrieved instead from
30
//! the associated Fields mentioned above.
31
//!
32
//! Note: The `tracing` crate requires trace metadata to be static. This does not work
33
//! for wasm code in substrate, as it is regularly updated with new code from on-chain
34
//! events. The workaround for this is for the wasm tracing wrappers to put the
35
//! `name` and `target` data in the `values` map (normally they would be in the static
36
//! metadata assembled at compile time).
37

            
38
#![cfg_attr(not(feature = "std"), no_std)]
39

            
40
extern crate alloc;
41

            
42
#[cfg(feature = "std")]
43
use tracing;
44
pub use tracing::{
45
	debug, debug_span, error, error_span, event, info, info_span, span, trace, trace_span, warn,
46
	warn_span, Level, Span,
47
};
48

            
49
pub use crate::types::{
50
	WasmEntryAttributes, WasmFieldName, WasmFields, WasmLevel, WasmMetadata, WasmValue,
51
	WasmValuesSet,
52
};
53
#[cfg(feature = "std")]
54
pub use crate::types::{WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER};
55

            
56
/// Tracing facilities and helpers.
57
///
58
/// This is modeled after the `tracing`/`tracing-core` interface and uses that more or
59
/// less directly for the native side. Because of certain optimisations the these crates
60
/// have done, the wasm implementation diverges slightly and is optimised for that use
61
/// case (like being able to cross the wasm/native boundary via scale codecs).
62
///
63
/// One of said optimisations is that all macros will yield to a `noop` in non-std unless
64
/// the `with-tracing` feature is explicitly activated. This allows you to just use the
65
/// tracing wherever you deem fit and without any performance impact by default. Only if
66
/// the specific `with-tracing`-feature is activated on this crate will it actually include
67
/// the tracing code in the non-std environment.
68
///
69
/// Because of that optimisation, you should not use the `span!` and `span_*!` macros
70
/// directly as they yield nothing without the feature present. Instead you should use
71
/// `enter_span!` and `within_span!` – which would strip away even any parameter conversion
72
/// you do within the span-definition (and thus optimise your performance). For your
73
/// convenience you directly specify the `Level` and name of the span or use the full
74
/// feature set of `span!`/`span_*!` on it:
75
///
76
/// # Example
77
///
78
/// ```rust
79
/// sp_tracing::enter_span!(sp_tracing::Level::TRACE, "fn wide span");
80
/// {
81
/// 		sp_tracing::enter_span!(sp_tracing::trace_span!("outer-span"));
82
/// 		{
83
/// 			sp_tracing::enter_span!(sp_tracing::Level::TRACE, "inner-span");
84
/// 			// ..
85
/// 		}  // inner span exists here
86
/// 	} // outer span exists here
87
///
88
/// sp_tracing::within_span! {
89
/// 		sp_tracing::debug_span!("debug-span", you_can_pass="any params");
90
///     1 + 1;
91
///     // some other complex code
92
/// } // debug span ends here
93
/// ```
94
///
95
///
96
/// # Setup
97
///
98
/// This project only provides the macros and facilities to manage tracing
99
/// it doesn't implement the tracing subscriber or backend directly – that is
100
/// up to the developer integrating it into a specific environment. In native
101
/// this can and must be done through the regular `tracing`-facilities, please
102
/// see their documentation for details.
103
///
104
/// On the wasm-side we've adopted a similar approach of having a global
105
/// `TracingSubscriber` that the macros call and that does the actual work
106
/// of tracking. To provide your tracking, you must implement `TracingSubscriber`
107
/// and call `set_tracing_subscriber` at the very beginning of your execution –
108
/// the default subscriber is doing nothing, so any spans or events happening before
109
/// will not be recorded!
110
mod types;
111

            
112
/// Try to init a simple tracing subscriber with log compatibility layer.
113
///
114
/// Ignores any error. Useful for testing.
115
#[cfg(feature = "std")]
116
pub fn try_init_simple() {
117
	let _ = tracing_subscriber::fmt()
118
		.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
119
		.with_writer(std::io::stderr)
120
		.try_init();
121
}
122

            
123
/// Init a tracing subscriber for logging in tests.
124
///
125
/// Be aware that this enables `TRACE` by default. It also ignores any error
126
/// while setting up the logger.
127
///
128
/// The logs are not shown by default, logs are only shown when the test fails
129
/// or if [`nocapture`](https://doc.rust-lang.org/cargo/commands/cargo-test.html#display-options)
130
/// is being used.
131
#[cfg(feature = "std")]
132
pub fn init_for_tests() {
133
	let _ = tracing_subscriber::fmt()
134
		.with_max_level(tracing::Level::TRACE)
135
		.with_test_writer()
136
		.try_init();
137
}
138

            
139
/// Runs given code within a tracing span, measuring it's execution time.
140
///
141
/// If tracing is not enabled, the code is still executed. Pass in level and name or
142
/// use any valid `sp_tracing::Span`followed by `;` and the code to execute,
143
///
144
/// # Example
145
///
146
/// ```
147
/// sp_tracing::within_span! {
148
///     sp_tracing::Level::TRACE,
149
///     "test-span";
150
///     1 + 1;
151
///     // some other complex code
152
/// }
153
///
154
/// sp_tracing::within_span! {
155
///     sp_tracing::span!(sp_tracing::Level::WARN, "warn-span", you_can_pass="any params");
156
///     1 + 1;
157
///     // some other complex code
158
/// }
159
///
160
/// sp_tracing::within_span! {
161
///     sp_tracing::debug_span!("debug-span", you_can_pass="any params");
162
///     1 + 1;
163
///     // some other complex code
164
/// }
165
/// ```
166
#[cfg(any(feature = "std", feature = "with-tracing"))]
167
#[macro_export]
168
macro_rules! within_span {
169
	(
170
		$span:expr;
171
		$( $code:tt )*
172
	) => {
173
		$span.in_scope(||
174
67287994
			{
175
67287994
				$( $code )*
176
			}
177
		)
178
	};
179
	(
180
		$lvl:expr,
181
		$name:expr;
182
		$( $code:tt )*
183
	) => {
184
		{
185
			$crate::within_span!($crate::span!($lvl, $name); $( $code )*)
186
		}
187
	};
188
}
189

            
190
#[cfg(all(not(feature = "std"), not(feature = "with-tracing")))]
191
#[macro_export]
192
macro_rules! within_span {
193
	(
194
		$span:stmt;
195
		$( $code:tt )*
196
	) => {
197
		$( $code )*
198
	};
199
	(
200
		$lvl:expr,
201
		$name:expr;
202
		$( $code:tt )*
203
	) => {
204
		$( $code )*
205
	};
206
}
207

            
208
/// Enter a span - noop for `no_std` without `with-tracing`
209
#[cfg(all(not(feature = "std"), not(feature = "with-tracing")))]
210
#[macro_export]
211
macro_rules! enter_span {
212
	( $lvl:expr, $name:expr ) => {};
213
	( $name:expr ) => {}; // no-op
214
}
215

            
216
/// Enter a span.
217
///
218
/// The span will be valid, until the scope is left. Use either level and name
219
/// or pass in any valid `sp_tracing::Span` for extended usage. The span will
220
/// be exited on drop – which is at the end of the block or to the next
221
/// `enter_span!` calls, as this overwrites the local variable. For nested
222
/// usage or to ensure the span closes at certain time either put it into a block
223
/// or use `within_span!`
224
///
225
/// # Example
226
///
227
/// ```
228
/// sp_tracing::enter_span!(sp_tracing::Level::TRACE, "test-span");
229
/// // previous will be dropped here
230
/// sp_tracing::enter_span!(
231
/// 	sp_tracing::span!(sp_tracing::Level::DEBUG, "debug-span", params="value"));
232
/// sp_tracing::enter_span!(sp_tracing::info_span!("info-span",  params="value"));
233
///
234
/// {
235
/// 		sp_tracing::enter_span!(sp_tracing::Level::TRACE, "outer-span");
236
/// 		{
237
/// 			sp_tracing::enter_span!(sp_tracing::Level::TRACE, "inner-span");
238
/// 			// ..
239
/// 		}  // inner span exists here
240
/// 	} // outer span exists here
241
/// ```
242
#[cfg(any(feature = "std", feature = "with-tracing"))]
243
#[macro_export]
244
macro_rules! enter_span {
245
	( $span:expr ) => {
246
		// Calling this twice in a row will overwrite (and drop) the earlier
247
		// that is a _documented feature_!
248
		let __within_span__ = $span;
249
		let __tracing_guard__ = __within_span__.enter();
250
	};
251
	( $lvl:expr, $name:expr ) => {
252
		$crate::enter_span!($crate::span!($lvl, $name))
253
	};
254
}