Skip to content

Commit ed87377

Browse files
committed
smite: add NyxLogger for debugging in Nyx mode
Enables scenario output to be printed in Nyx mode when SMITE_NYX_LOG is enabled.
1 parent bf52f5f commit ed87377

3 files changed

Lines changed: 76 additions & 1 deletion

File tree

smite/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub mod bitcoin;
1919
pub mod bolt;
2020
pub mod channel_tx;
2121
pub mod noise;
22+
#[cfg(feature = "nyx")]
23+
pub mod nyx_log;
2224
pub mod oracles;
2325
pub mod process;
2426
pub mod runners;

smite/src/nyx_log.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! Logger that forwards `log` records to the Nyx host via `nyx_println`.
2+
//!
3+
//! In Nyx mode the guest's stdout/stderr is discarded, so `simple_logger`
4+
//! output never reaches the host. This logger instead routes each record
5+
//! through `nyx_println` for debugging. Honors the `RUST_LOG` log level.
6+
//!
7+
//! This logger is only installed when the `nyx` feature is active and both
8+
//! `SMITE_NYX` and `SMITE_NYX_LOG` are set.
9+
10+
use std::ffi::c_char;
11+
12+
use log::{LevelFilter, Log, Metadata, Record};
13+
14+
struct NyxLogger {
15+
level: LevelFilter,
16+
}
17+
18+
impl Log for NyxLogger {
19+
fn enabled(&self, metadata: &Metadata) -> bool {
20+
metadata.level() <= self.level
21+
}
22+
23+
fn log(&self, record: &Record) {
24+
if !self.enabled(record.metadata()) {
25+
return;
26+
}
27+
let line = format!(
28+
"{:<5} [{}] {}",
29+
record.level(),
30+
record.target(),
31+
record.args()
32+
);
33+
// SAFETY: The line.len() bytes at the line pointer are valid for the
34+
// duration of the call.
35+
unsafe {
36+
smite_nyx_sys::nyx_println(line.as_ptr().cast::<c_char>(), line.len());
37+
}
38+
}
39+
40+
fn flush(&self) {}
41+
}
42+
43+
/// Reads the desired level from `RUST_LOG` (default `info`).
44+
fn level_from_env() -> LevelFilter {
45+
std::env::var("RUST_LOG")
46+
.ok()
47+
.and_then(|v| v.trim().parse().ok())
48+
.unwrap_or(LevelFilter::Info)
49+
}
50+
51+
/// Installs the Nyx logger as the global `log` logger.
52+
///
53+
/// # Panics
54+
///
55+
/// Panics if a global logger has already been set.
56+
pub fn init() {
57+
let level = level_from_env();
58+
log::set_boxed_logger(Box::new(NyxLogger { level })).expect("logger not already set");
59+
log::set_max_level(level);
60+
}

smite/src/scenarios.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ pub trait Scenario: Sized {
8484
fn run(&mut self, input: &[u8]) -> ScenarioResult;
8585
}
8686

87+
/// Installs the global `log` logger.
88+
///
89+
/// Defaults to `simple_logger`. When the `nyx` feature is enabled and both
90+
/// `SMITE_NYX` and `SMITE_NYX_LOG` are set, `nyx_log` is installed instead.
91+
fn init_logging() {
92+
#[cfg(feature = "nyx")]
93+
if std::env::var("SMITE_NYX").is_ok() && std::env::var("SMITE_NYX_LOG").is_ok() {
94+
crate::nyx_log::init();
95+
return;
96+
}
97+
simple_logger::init_with_env().expect("logger not already set");
98+
}
99+
87100
/// Run a scenario with the standard runner.
88101
///
89102
/// This is the main entry point for smite scenario binaries. It initializes
@@ -98,7 +111,7 @@ pub fn smite_run<S: Scenario>() -> std::process::ExitCode {
98111

99112
use crate::runners::{Runner, StdRunner};
100113

101-
simple_logger::init_with_env().expect("Failed to initialize logger");
114+
init_logging();
102115

103116
// Install a panic hook so that panics in the scenario itself (e.g., failed
104117
// expect() calls) are reported as crashes rather than silent timeouts.

0 commit comments

Comments
 (0)