Skip to content

Commit

Permalink
Sync with paritytech#7769
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondkfcheung committed Mar 5, 2025
1 parent 1258918 commit d16e6e4
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 89 deletions.
2 changes: 1 addition & 1 deletion polkadot/xcm/xcm-simulator/example/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ fn reserve_transfer_with_error() {
MockNet::reset();

// Execute XCM Transfer and Capture Logs
let (log_capture, subscriber) = init_log_capture(Level::ERROR);
let (log_capture, subscriber) = init_log_capture(Level::ERROR, false);
subscriber::with_default(subscriber, || {
let invalid_dest = Box::new(Parachain(9999).into());
let withdraw_amount = 123;
Expand Down
2 changes: 1 addition & 1 deletion prdoc/pr_7234.prdoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ crates:
- name: xcm-runtime-apis
bump: minor
- name: xcm-simulator-example
bump: minor
bump: patch
- name: xcm-simulator-fuzzer
bump: patch
- name: pallet-contracts-mock-network
Expand Down
144 changes: 57 additions & 87 deletions substrate/primitives/tracing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ mod types;
///
/// Related functions:
/// - [`init_for_tests()`]: Enables `TRACE` level.
/// - [`test_log_capture::init_log_capture_for_tests()`]: Captures logs and outputs `TRACE` level.
/// - [`test_log_capture::init_log_capture()`]: Captures logs for assertions and/or outputs logs.
/// - [`capture_test_logs!()`]: A macro for capturing logs within test blocks.
#[cfg(feature = "std")]
pub fn try_init_simple() {
let _ = tracing_subscriber::fmt()
Expand All @@ -138,7 +139,8 @@ pub fn try_init_simple() {
///
/// Related functions:
/// - [`try_init_simple()`]: Uses the default filter.
/// - [`test_log_capture::init_log_capture_for_tests()`]: Captures logs and outputs `TRACE` level.
/// - [`test_log_capture::init_log_capture()`]: Captures logs for assertions and/or outputs logs.
/// - [`capture_test_logs!()`]: A macro for capturing logs within test blocks.
#[cfg(feature = "std")]
pub fn init_for_tests() {
let _ = tracing_subscriber::fmt()
Expand Down Expand Up @@ -366,15 +368,18 @@ pub mod test_log_capture {
}
}

/// Initialises a log capture utility for testing.
/// Initialises a log capture utility for testing, with optional log printing.
///
/// This function sets up a `LogCapture` instance to capture logs during test execution.
/// It also configures a `tracing_subscriber` with the specified maximum log level
/// and a writer that directs logs to `LogCapture`.
/// and a writer that directs logs to `LogCapture`. If `print_logs` is enabled, logs
/// up to `max_level` are also printed to the test output.
///
/// # Arguments
///
/// * `max_level` - The maximum log level to capture, which can be converted into `LevelFilter`.
/// * `max_level` - The maximum log level to capture and print, which can be converted into
/// `LevelFilter`.
/// * `print_logs` - If `true`, logs up to `max_level` will also be printed to the test output.
///
/// # Returns
///
Expand All @@ -390,102 +395,47 @@ pub mod test_log_capture {
/// tracing::{info, subscriber, Level},
/// };
///
/// let (log_capture, subscriber) = init_log_capture(Level::INFO);
/// let (log_capture, subscriber) = init_log_capture(Level::INFO, false);
/// subscriber::with_default(subscriber, || {
/// info!("This log will be captured");
/// assert!(log_capture.contains("This log will be captured"));
/// });
/// ```
///
/// Related functions/macros:
/// - [`init_log_capture_for_tests()`]: Captures logs and outputs `TRACE` level.
/// - `capture_test_logs!()`: A macro for capturing logs during test execution.
pub fn init_log_capture(
max_level: impl Into<LevelFilter>,
) -> (LogCapture, impl tracing::Subscriber + Send + Sync) {
do_init_log_capture(max_level, false)
}

/// Initialises a log capture utility for tests, ensuring both **log capturing** and **test
/// output visibility**.
///
/// This function is useful when you need to:
/// - **Capture logs for assertions**, like [`init_log_capture()`].
/// - **Ensure logs up to `TRACE` level are printed to the test output**, similar to
/// `sp_tracing::init_for_tests()`.
///
/// # Usage Guide
///
/// Use **`init_log_capture_for_tests()`** when you need **both**: logs captured for assertions
/// **and** printed to the console.
/// - If you only need to **capture logs for assertions** without printing them, use
/// [`init_log_capture()`].
/// - If you only need to **print logs** during tests but not capture them, use
/// `init_log_capture(max_level, false)`.
/// - If you need both **capturing and printing logs**, use `init_log_capture(max_level, true)`.
/// - If you only need to **print logs** but not capture them, use
/// `sp_tracing::init_for_tests()`.
/// - If you prefer a macro-based approach, use `capture_test_logs!()`, which internally calls
/// `init_log_capture()`.
///
/// # Returns
///
/// A tuple containing:
/// - `LogCapture`: The log capture instance for assertions.
/// - `Subscriber`: A `tracing_subscriber` that captures and prints logs.
///
/// # Examples
///
/// ```
/// use sp_tracing::{
/// test_log_capture::init_log_capture_for_tests,
/// tracing::{debug, subscriber},
/// };
///
/// let (log_capture, subscriber) = init_log_capture_for_tests();
/// subscriber::with_default(subscriber, || {
/// debug!("This log will be captured and printed to test output");
/// assert!(log_capture.contains("This log will be captured and printed to test output"));
/// });
/// ```
pub fn init_log_capture_for_tests() -> (LogCapture, impl tracing::Subscriber + Send + Sync) {
do_init_log_capture(LevelFilter::TRACE, true)
}

/// Internal function to initialise log capture with configurable test mode.
///
/// - Creates a `LogCapture` instance to store captured logs.
/// - Configures a `tracing_subscriber` with a custom log writer.
/// - Optionally adds a layer to print logs when `for_test` is `true`.
///
/// # Arguments
///
/// * `max_level` - The maximum log level to capture.
/// * `for_tests` - If `true`, adds a layer to print logs in test output.
///
/// # Returns
///
/// A tuple containing:
/// - `LogCapture`: The log capture instance.
/// - `Subscriber`: A combined `tracing_subscriber` with capture and optional test layers.
fn do_init_log_capture(
pub fn init_log_capture(
max_level: impl Into<LevelFilter>,
for_tests: bool,
print_logs: bool,
) -> (LogCapture, impl tracing::Subscriber + Send + Sync) {
// Create a new log capture instance
let log_capture = LogCapture::new();

// Convert the max log level into LevelFilter
let level_filter = max_level.into();

// Convert the max log level into LevelFilter
let level_filter = max_level.into();

// Create a layer for capturing logs into LogCapture
let capture_layer = fmt::layer()
.with_writer(log_capture.writer()) // Use LogCapture as the writer
.with_filter(max_level.into()); // Set the max log level
.with_filter(level_filter); // Set the max log level

// Base subscriber with log capturing
let subscriber = Registry::default().with(capture_layer);

// If in test mode, add a layer that prints logs to test output
let test_layer = if for_tests {
// If `print_logs` is enabled, add a layer that prints logs to test output up to `max_level`
let test_layer = if print_logs {
Some(
fmt::layer()
.with_test_writer() // Use test writer for test output
.with_filter(LevelFilter::TRACE), // Capture all logs in tests
.with_test_writer() // Direct logs to test output
.with_filter(level_filter), // Apply the same max log level filter
)
} else {
None
Expand All @@ -499,43 +449,63 @@ pub mod test_log_capture {

/// Macro for capturing logs during test execution.
///
/// It sets up a log subscriber with an optional maximum log level and captures the output.
/// This macro sets up a log subscriber with a specified maximum log level
/// and an option to print logs to the test output while capturing them.
///
/// # Arguments
///
/// - `$max_level`: The maximum log level to capture.
/// - `$print_logs`: Whether to also print logs to the test output.
/// - `$test`: The block of code where logs are captured.
///
/// # Examples
///
/// ```
/// use sp_tracing::{
/// capture_test_logs,
/// tracing::{info, warn, Level},
/// };
///
/// let log_capture = capture_test_logs!(Level::WARN, {
/// // Capture logs at WARN level without printing them
/// let log_capture = capture_test_logs!(Level::WARN, false, {
/// info!("Captured info message");
/// warn!("Captured warning");
/// });
///
/// assert!(!log_capture.contains("Captured log message"));
/// assert!(!log_capture.contains("Captured info message"));
/// assert!(log_capture.contains("Captured warning"));
///
/// // Capture logs at TRACE level and also print them
/// let log_capture = capture_test_logs!(Level::TRACE, true, {
/// info!("This will be captured and printed");
/// });
///
/// assert!(log_capture.contains("This will be captured and printed"));
/// ```
///
/// Related functions:
/// # Related functions:
/// - [`init_log_capture()`]: Captures logs for assertions.
/// - [`init_log_capture_for_tests()`]: Captures logs and outputs `TRACE` level.
/// - `sp_tracing::init_for_tests()`: Outputs logs but does not capture them.
#[macro_export]
macro_rules! capture_test_logs {
// Case when max_level is provided
($max_level:expr, $test:block) => {{
// Case when max_level and print_logs are provided
($max_level:expr, $print_logs:expr, $test:block) => {{
let (log_capture, subscriber) =
sp_tracing::test_log_capture::init_log_capture($max_level);
sp_tracing::test_log_capture::init_log_capture($max_level, $print_logs);

sp_tracing::tracing::subscriber::with_default(subscriber, || $test);

log_capture
}};

// Case when max_level is omitted (defaults to DEBUG)
// Case when only max_level is provided (defaults to not printing logs)
($max_level:expr, $test:block) => {{
capture_test_logs!($max_level, false, $test)
}};

// Case when max_level is omitted (defaults to DEBUG, no printing)
($test:block) => {{
capture_test_logs!(sp_tracing::tracing::Level::DEBUG, $test)
capture_test_logs!(sp_tracing::tracing::Level::DEBUG, false, $test)
}};
}
}

0 comments on commit d16e6e4

Please sign in to comment.