tetcore_tracing/lib.rs
1// This file is part of Tetcore.
2
3// Copyright (C) 2020-2021 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//! Tetcore tracing primitives and macros.
19//!
20//! To trace functions or invidual code in Tetcore, 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#![cfg_attr(not(feature = "std"), no_std)]
33
34/// Tracing facilities and helpers.
35///
36/// This is modeled after the `tracing`/`tracing-core` interface and uses that more or
37/// less directly for the native side. Because of certain optimisations the these crates
38/// have done, the wasm implementation diverges slightly and is optimised for thtat use
39/// case (like being able to cross the wasm/native boundary via scale codecs).
40///
41/// One of said optimisations is that all macros will yield to a `noop` in non-std unless
42/// the `with-tracing` feature is explicitly activated. This allows you to just use the
43/// tracing wherever you deem fit and without any performance impact by default. Only if
44/// the specific `with-tracing`-feature is activated on this crate will it actually include
45/// the tracing code in the non-std environment.
46///
47/// Because of that optimisation, you should not use the `span!` and `span_*!` macros
48/// directly as they yield nothing without the feature present. Instead you should use
49/// `enter_span!` and `within_span!` – which would strip away even any parameter conversion
50/// you do within the span-definition (and thus optimise your performance). For your
51/// convineience you directly specify the `Level` and name of the span or use the full
52/// feature set of `span!`/`span_*!` on it:
53///
54/// # Example
55///
56/// ```rust
57/// tetcore_tracing::enter_span!(tetcore_tracing::Level::TRACE, "fn wide span");
58/// {
59/// tetcore_tracing::enter_span!(tetcore_tracing::trace_span!("outer-span"));
60/// {
61/// tetcore_tracing::enter_span!(tetcore_tracing::Level::TRACE, "inner-span");
62/// // ..
63/// } // inner span exists here
64/// } // outer span exists here
65///
66/// tetcore_tracing::within_span! {
67/// tetcore_tracing::debug_span!("debug-span", you_can_pass="any params");
68/// 1 + 1;
69/// // some other complex code
70/// } // debug span ends here
71///
72/// ```
73///
74///
75/// # Setup
76///
77/// This project only provides the macros and facilities to manage tracing
78/// it doesn't implement the tracing subscriber or backend directly – that is
79/// up to the developer integrating it into a specific environment. In native
80/// this can and must be done through the regular `tracing`-facitilies, please
81/// see their documentation for details.
82///
83/// On the wasm-side we've adopted a similar approach of having a global
84/// `TracingSubscriber` that the macros call and that does the actual work
85/// of tracking. To provide your tracking, you must implement `TracingSubscriber`
86/// and call `set_tracing_subscriber` at the very beginning of your execution –
87/// the default subscriber is doing nothing, so any spans or events happening before
88/// will not be recorded!
89///
90
91mod types;
92
93#[cfg(feature = "std")]
94use tracing;
95
96pub use tracing::{
97 debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span,
98 span, event, Level, Span,
99};
100
101pub use crate::types::{
102 WasmMetadata, WasmEntryAttributes, WasmValuesSet, WasmValue, WasmFields, WasmLevel, WasmFieldName
103};
104
105
106/// Try to init a simple tracing subscriber with log compatibility layer.
107/// Ignores any error. Useful for testing.
108#[cfg(feature = "std")]
109pub fn try_init_simple() {
110 let _ = tracing_subscriber::fmt()
111 .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
112 .with_writer(std::io::stderr).try_init();
113}
114
115#[cfg(feature = "std")]
116pub use crate::types::{
117 WASM_NAME_KEY, WASM_TARGET_KEY, WASM_TRACE_IDENTIFIER
118};
119
120
121/// Runs given code within a tracing span, measuring it's execution time.
122///
123/// If tracing is not enabled, the code is still executed. Pass in level and name or
124/// use any valid `tetcore_tracing::Span`followe by `;` and the code to execute,
125///
126/// # Example
127///
128/// ```
129/// tetcore_tracing::within_span! {
130/// tetcore_tracing::Level::TRACE,
131/// "test-span";
132/// 1 + 1;
133/// // some other complex code
134/// }
135///
136/// tetcore_tracing::within_span! {
137/// tetcore_tracing::span!(tetcore_tracing::Level::WARN, "warn-span", you_can_pass="any params");
138/// 1 + 1;
139/// // some other complex code
140/// }
141///
142/// tetcore_tracing::within_span! {
143/// tetcore_tracing::debug_span!("debug-span", you_can_pass="any params");
144/// 1 + 1;
145/// // some other complex code
146/// }
147/// ```
148#[cfg(any(feature = "std", feature = "with-tracing"))]
149#[macro_export]
150macro_rules! within_span {
151 (
152 $span:expr;
153 $( $code:tt )*
154 ) => {
155 $span.in_scope(||
156 {
157 $( $code )*
158 }
159 )
160 };
161 (
162 $lvl:expr,
163 $name:expr;
164 $( $code:tt )*
165 ) => {
166 {
167 $crate::within_span!($crate::span!($lvl, $name); $( $code )*)
168 }
169 };
170}
171
172#[cfg(all(not(feature = "std"), not(feature = "with-tracing")))]
173#[macro_export]
174macro_rules! within_span {
175 (
176 $span:stmt;
177 $( $code:tt )*
178 ) => {
179 $( $code )*
180 };
181 (
182 $lvl:expr,
183 $name:expr;
184 $( $code:tt )*
185 ) => {
186 $( $code )*
187 };
188}
189
190
191/// Enter a span - noop for `no_std` without `with-tracing`
192#[cfg(all(not(feature = "std"), not(feature = "with-tracing")))]
193#[macro_export]
194macro_rules! enter_span {
195 ( $lvl:expr, $name:expr ) => ( );
196 ( $name:expr ) => ( ) // no-op
197}
198
199/// Enter a span.
200///
201/// The span will be valid, until the scope is left. Use either level and name
202/// or pass in any valid `tetcore_tracing::Span` for extended usage. The span will
203/// be exited on drop – which is at the end of the block or to the next
204/// `enter_span!` calls, as this overwrites the local variable. For nested
205/// usage or to ensure the span closes at certain time either put it into a block
206/// or use `within_span!`
207///
208/// # Example
209///
210/// ```
211/// tetcore_tracing::enter_span!(tetcore_tracing::Level::TRACE, "test-span");
212/// // previous will be dropped here
213/// tetcore_tracing::enter_span!(
214/// tetcore_tracing::span!(tetcore_tracing::Level::DEBUG, "debug-span", params="value"));
215/// tetcore_tracing::enter_span!(tetcore_tracing::info_span!("info-span", params="value"));
216///
217/// {
218/// tetcore_tracing::enter_span!(tetcore_tracing::Level::TRACE, "outer-span");
219/// {
220/// tetcore_tracing::enter_span!(tetcore_tracing::Level::TRACE, "inner-span");
221/// // ..
222/// } // inner span exists here
223/// } // outer span exists here
224///
225/// ```
226#[cfg(any(feature = "std", feature = "with-tracing"))]
227#[macro_export]
228macro_rules! enter_span {
229 ( $span:expr ) => {
230 // Calling this twice in a row will overwrite (and drop) the earlier
231 // that is a _documented feature_!
232 let __within_span__ = $span;
233 let __tracing_guard__ = __within_span__.enter();
234 };
235 ( $lvl:expr, $name:expr ) => {
236 $crate::enter_span!($crate::span!($lvl, $name))
237 };
238}