referrerpolicy=no-referrer-when-downgrade

frame_benchmarking_cli/pallet/
logging.rs

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
18use super::LOG_TARGET;
19use sp_core::{LogLevelFilter, RuntimeInterfaceLogLevel};
20use sp_runtime_interface::{
21	pass_by::{PassAs, PassFatPointerAndRead, ReturnAs},
22	runtime_interface,
23};
24use std::cell::OnceCell;
25
26thread_local! {
27	/// Log level filter that the runtime will use.
28	///
29	/// Must be initialized by the host before invoking the runtime executor. You may use `init` for
30	/// this or set it manually. The that can be set are either levels directly or filter like
31	// `warn,runtime=info`.
32	pub static RUNTIME_LOG: OnceCell<env_filter::Filter> = OnceCell::new();
33}
34
35/// Init runtime logger with the following priority (high to low):
36/// - CLI argument
37/// - Environment variable
38/// - Default logger settings
39pub fn init(arg: Option<String>) {
40	let filter_str = arg.unwrap_or_else(|| {
41		if let Ok(env) = std::env::var("RUNTIME_LOG") {
42			env
43		} else {
44			log::max_level().to_string()
45		}
46	});
47
48	let filter = env_filter::Builder::new()
49		.try_parse(&filter_str)
50		.expect("Invalid runtime log filter")
51		.build();
52
53	RUNTIME_LOG.with(|cell| {
54		cell.set(filter).expect("Can be set by host");
55		log::info!(target: LOG_TARGET, "Initialized runtime log filter to '{}'", filter_str);
56	});
57}
58
59/// Alternative implementation to `sp_runtime_interface::logging::HostFunctions` for benchmarking.
60#[runtime_interface]
61pub trait Logging {
62	#[allow(dead_code)]
63	fn log(
64		level: PassAs<RuntimeInterfaceLogLevel, u8>,
65		target: PassFatPointerAndRead<&str>,
66		message: PassFatPointerAndRead<&[u8]>,
67	) {
68		let Ok(message) = core::str::from_utf8(message) else {
69			log::error!(target: LOG_TARGET, "Runtime tried to log invalid UTF-8 data");
70			return;
71		};
72
73		let level = log::Level::from(level);
74		let metadata = log::MetadataBuilder::new().level(level).target(target).build();
75
76		if RUNTIME_LOG.with(|filter| filter.get().expect("Must be set by host").enabled(&metadata))
77		{
78			log::log!(target: target, level, "{}", message);
79		}
80	}
81
82	#[allow(dead_code)]
83	fn max_level() -> ReturnAs<LogLevelFilter, u8> {
84		RUNTIME_LOG
85			// .filter() gives us the max level of this filter
86			.with(|filter| filter.get().expect("Must be set by host").filter())
87			.into()
88	}
89}