如何在使用NEAR Workspaces-rs的Rust集成测试中查看日志并初始化日志记录器
解决NEAR workspaces-rs集成测试中看不到合约日志的问题
我明白你遇到的困境——用NEAR的workspaces-rs写集成测试时,合约里的日志死活出不来,哪怕试了env_logger的测试初始化也只看到测试代码自己的日志。这其实是因为NEAR合约的日志体系和普通Rust程序的日志不是一回事,咱们得换个思路处理:
核心原因:两类日志的本质区别
你在合约里用的log!(NEAR SDK提供的)或者换成的info!(Rust标准log crate),和测试代码里的日志走的是完全不同的路径:
- NEAR SDK的
log!是直接调用NEAR区块链的环境API(env::log_str),这些日志会被workspaces-rs的沙箱/测试网环境捕获,但默认不会自动输出到终端。 - 如果你换成Rust标准log的
info!,合约编译成Wasm后,log crate默认没有输出目标,自然也看不到任何日志。
方案1:继续用NEAR SDK的log!(推荐)
这是最简单的方式,只需要让workspaces-rs把捕获到的合约日志输出出来:
步骤1:在测试代码中正确初始化日志
确保你的测试里初始化env_logger时,包含workspaces-rs的日志级别(因为workspaces会把合约日志以info级别输出):
#[cfg(test)] mod tests { use workspaces::prelude::*; use log::info; fn init_test_logger() { // 初始化env_logger,设置日志级别为Info,适配测试环境 let _ = env_logger::builder() .filter_level(log::LevelFilter::Info) .is_test(true) .try_init(); } #[tokio::test] async fn test_remove_function() { init_test_logger(); // 创建沙箱环境 let worker = workspaces::sandbox().await.unwrap(); // 部署合约(这里假设你已经有合约字节码的处理逻辑) let contract = worker.dev_deploy(include_bytes!("../target/wasm32-unknown-unknown/release/your_contract.wasm")) .await.unwrap(); // 调用合约的remove方法 let result = contract.call(&worker, "remove") .args_json(serde_json::json!({ "key": "test_key", "recipient": "test_account.near" })) .transact() .await.unwrap(); // 你也可以直接从执行结果中手动取出日志打印 println!("合约执行日志: {:?}", result.logs()); } }
步骤2:运行测试时配置环境变量
在终端运行测试时,需要设置RUST_LOG环境变量,让workspaces-rs输出合约日志:
RUST_LOG=workspaces=info cargo test -- --nocapture
RUST_LOG=workspaces=info:告诉env_logger输出workspaces-rs的info级别日志(合约日志就在这里面)--nocapture:禁止Rust测试框架捕获输出,让日志实时显示在终端(如果不需要实时,也可以不加,测试结束后会显示所有日志)
方案2:用Rust标准log crate的info!等宏
如果你更习惯用标准log的宏,需要在合约里把日志转发到NEAR的环境日志API,这样workspaces-rs才能捕获到:
步骤1:在合约中实现自定义Logger
在你的合约代码里添加一个简单的Logger,把log crate的日志转发到env::log_str:
use near_sdk::{env, near_bindgen}; use log::{Level, LevelFilter, Metadata, Record}; // 自定义Logger,把log crate的日志转发到NEAR环境日志 struct NearEnvLogger; impl log::Log for NearEnvLogger { fn enabled(&self, metadata: &Metadata) -> bool { // 这里可以设置你想要的日志级别 metadata.level() <= Level::Info } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { // 格式化日志并调用NEAR的环境日志API env::log_str(&format!("[{}] {}", record.level(), record.args())); } } fn flush(&self) {} } #[near_bindgen] #[derive(Default)] pub struct Contract; #[near_bindgen] impl Contract { #[init] pub fn new() -> Self { // 初始化log crate的Logger log::set_logger(&NearEnvLogger).unwrap(); log::set_max_level(LevelFilter::Info); Self::default() } pub fn remove(&mut self, key: String, recipient: String) { // 现在可以用标准log的info!宏了 info!("Removed {} from {}", &key, &recipient); // 你的业务逻辑... } }
步骤2:测试端配置和方案1一样
按照方案1的测试代码初始化日志,然后用同样的命令运行测试,就能看到标准log宏输出的日志了。
常见排查点
- 确保你的合约部署和调用逻辑正确,如果合约没执行到对应的日志代码,自然看不到输出。
- 检查
RUST_LOG的设置是否正确,比如如果用了debug级别,可以改成RUST_LOG=workspaces=debug看更详细的日志。 - 确认测试函数用了
#[tokio::test],因为workspaces-rs是基于tokio异步运行时的。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

