sc_tracing/logging/
directives.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Substrate.
3
4// Substrate is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Substrate is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
16
17use parking_lot::Mutex;
18use std::sync::OnceLock;
19use tracing_subscriber::{
20	filter::Directive, fmt as tracing_fmt, layer, reload::Handle, EnvFilter, Registry,
21};
22
23// Handle to reload the tracing log filter
24static FILTER_RELOAD_HANDLE: OnceLock<Handle<EnvFilter, SCSubscriber>> = OnceLock::new();
25// Directives that are defaulted to when resetting the log filter
26static DEFAULT_DIRECTIVES: OnceLock<Mutex<Vec<String>>> = OnceLock::new();
27// Current state of log filter
28static CURRENT_DIRECTIVES: OnceLock<Mutex<Vec<String>>> = OnceLock::new();
29
30/// Add log filter directive(s) to the defaults
31///
32/// The syntax is identical to the CLI `<target>=<level>`:
33///
34/// `sync=debug,state=trace`
35pub(crate) fn add_default_directives(directives: &str) {
36	DEFAULT_DIRECTIVES
37		.get_or_init(|| Mutex::new(Vec::new()))
38		.lock()
39		.push(directives.to_owned());
40	add_directives(directives);
41}
42
43/// Add directives to current directives
44pub fn add_directives(directives: &str) {
45	CURRENT_DIRECTIVES
46		.get_or_init(|| Mutex::new(Vec::new()))
47		.lock()
48		.push(directives.to_owned());
49}
50
51/// Parse `Directive` and add to default directives if successful.
52///
53/// Ensures the supplied directive will be restored when resetting the log filter.
54pub(crate) fn parse_default_directive(directive: &str) -> super::Result<Directive> {
55	let dir = directive.parse()?;
56	add_default_directives(directive);
57	Ok(dir)
58}
59
60/// Reload the logging filter with the supplied directives added to the existing directives
61pub fn reload_filter() -> Result<(), String> {
62	let mut env_filter = EnvFilter::default();
63	if let Some(current_directives) = CURRENT_DIRECTIVES.get() {
64		// Use join and then split in case any directives added together
65		for directive in current_directives.lock().join(",").split(',').map(|d| d.parse()) {
66			match directive {
67				Ok(dir) => env_filter = env_filter.add_directive(dir),
68				Err(invalid_directive) => {
69					log::warn!(
70						target: "tracing",
71						"Unable to parse directive while setting log filter: {:?}",
72						invalid_directive,
73					);
74				},
75			}
76		}
77	}
78
79	// Set the max logging level for the `log` macros.
80	let max_level_hint =
81		tracing_subscriber::Layer::<tracing_subscriber::FmtSubscriber>::max_level_hint(&env_filter);
82	log::set_max_level(super::to_log_level_filter(max_level_hint));
83
84	log::debug!(target: "tracing", "Reloading log filter with: {}", env_filter);
85	FILTER_RELOAD_HANDLE
86		.get()
87		.ok_or("No reload handle present")?
88		.reload(env_filter)
89		.map_err(|e| format!("{}", e))
90}
91
92/// Resets the log filter back to the original state when the node was started.
93///
94/// Includes substrate defaults and CLI supplied directives.
95pub fn reset_log_filter() -> Result<(), String> {
96	let directive = DEFAULT_DIRECTIVES.get_or_init(|| Mutex::new(Vec::new())).lock().clone();
97
98	*CURRENT_DIRECTIVES.get_or_init(|| Mutex::new(Vec::new())).lock() = directive;
99	reload_filter()
100}
101
102/// Initialize FILTER_RELOAD_HANDLE, only possible once
103pub(crate) fn set_reload_handle(handle: Handle<EnvFilter, SCSubscriber>) {
104	let _ = FILTER_RELOAD_HANDLE.set(handle);
105}
106
107// The layered Subscriber as built up in `LoggerBuilder::init()`.
108// Used in the reload `Handle`.
109type SCSubscriber<
110	N = tracing_fmt::format::DefaultFields,
111	E = crate::logging::EventFormat,
112	W = crate::logging::DefaultLogger,
113> = layer::Layered<tracing_fmt::Layer<Registry, N, E, W>, Registry>;