开发工具与日志
本教程共 48 篇 · 第 42 篇 · 更新于 2026-08-09 · 约 10 分钟阅读
本节目标:读完你能打开 Tauri 的开发者工具(DevTools),分清 Rust 控制台和 WebView 控制台各自看什么,并用 plugin-log 插件搭建统一的日志系统。
开发 Tauri 应用时,你实际上在同时写两套代码:Rust 端(后端)和前端(WebView 里的 JS)。出了 bug,你也需要在两个地方分别排查。Tauri 提供了配套的调试工具,让你能在两端都看到错误信息、打印日志、设断点。本章把这些调试手段整理一遍,从最常用的 DevTools 开始。
打开 WebView 的 DevTools
WebView 里的页面就是普通的前端代码,调试方式和 Chrome 开发者工具几乎一样。右键点击应用窗口内部,选择「检查(Inspect Element)」,就能打开 inspector(检查器)面板。
也可以用快捷键:
- Windows / Linux:
Ctrl + Shift + I - macOS:
Command + Option + I
打开后面板长得和 Chrome DevTools 一模一样:Elements 看 DOM、Console 打日志、Network 看请求、Sources 断点调试 JS,都能用。
Note不同平台的 inspector 底层不同:Windows 用的是 Microsoft Edge DevTools,macOS 用 Safari 的检查器,Linux 用 webkit2gtk 的 WebInspector。界面略有差异,但核心功能一致。
用代码控制 DevTools
有时候你想在应用启动时自动打开 DevTools,而不是手动右键。Tauri 提供了两个 Rust API 来控制它:
use tauri::Manager;
tauri::Builder::default()
.setup(|app| {
#[cfg(debug_assertions)]
{
let window = app.get_webview_window("main").unwrap();
window.open_devtools();
}
Ok(())
})
.run(tauri::generate_context!())
.expect("运行 Tauri 应用时出错");
open_devtools() 打开面板,close_devtools() 关闭。这里用 #[cfg(debug_assertions)] 包起来,确保只在调试构建中生效,不会泄漏到生产包里。
WarningmacOS 上 devtools API 是私有接口。如果在
Cargo.toml里启用了devtoolsfeature 并发布到 App Store,审核会被拒。仅在开发阶段使用。
在生产构建中启用 DevTools
默认情况下,DevTools 只在 tauri dev 和 tauri build --debug 时可用。如果你需要在生产包里调试,有两种方式。
第一种是构建调试版本:
tauri build --debug
生成的应用带 DevTools,放在 src-tauri/target/debug/bundle 目录下。
第二种是在 Cargo.toml 里启用 devtools feature:
[dependencies]
tauri = { version = "2", features = ["devtools"] }
这样即使 tauri build(release)也会带 DevTools。但如上所述,macOS App Store 不接受这种包。
Rust 控制台:看后端日志的地方
前端日志在 DevTools Console 里看,Rust 端的日志去哪看?答案是你运行 tauri dev 的那个终端。
在 Rust 代码里用 println! 打印的内容,会直接输出到终端:
println!("来自 Rust 的消息:{}", msg);
如果 tauri dev 崩溃了,你可能需要看完整的堆栈跟踪。在 Linux 和 macOS 上:
RUST_BACKTRACE=1 tauri dev
Windows(PowerShell):
$env:RUST_BACKTRACE=1
tauri dev
Rust 编译器本身的报错也很有用——它会告诉你哪一行出了什么错,甚至建议修正。比如拼错变量名时:
error[E0425]: cannot find value `sun` in this scope
--> src/main.rs:11:5
|
11 | sun += i.to_string().parse::<u64>().unwrap();
| ^^^ help: a local variable with a similar name exists: `sum`
区分开发模式与生产模式
调试代码只在开发时跑,生产环境里不该出现。Tauri 提供了两套判断机制:
fn main() {
// 方式一:cfg!(dev) —— 只在 tauri dev 时为 true
if cfg!(dev) {
println!("开发模式");
} else {
println!("生产模式");
}
// 方式二:cfg!(debug_assertions) —— dev 和 build --debug 都为 true
if cfg!(debug_assertions) {
println!("调试构建");
}
// 方式三:tauri::is_dev() —— 返回 bool
let is_dev = tauri::is_dev();
println!("是否开发模式:{}", is_dev);
}
两者的区别:cfg!(dev) 只在 tauri dev 时为 true;cfg!(debug_assertions) 在 tauri dev 和 tauri build --debug 时都为 true。按需选用。
CrabNebula DevTools
除了浏览器自带的 inspector,Tauri 的合作伙伴 CrabNebula 提供了一个独立的 DevTools 应用,能捕获应用的资源、配置、日志和性能数据,用 Web 界面可视化展示。
安装方式:
cargo add tauri-plugin-devtools@2
在 main.rs 里尽早初始化:
fn main() {
#[cfg(debug_assertions)]
let devtools = tauri_plugin_devtools::init();
let mut builder = tauri::Builder::default();
#[cfg(debug_assertions)]
{
builder = builder.plugin(devtools);
}
builder
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Note建议只在调试构建中启用这个插件。用
#[cfg(debug_assertions)]包裹即可。更多用法参考 CrabNebula DevTools 文档。
日志插件:plugin-log
println! 够用但太原始——没有时间戳、没有日志级别、不能写文件。Tauri 官方提供了 tauri-plugin-log 插件,支持多级别日志、多目标输出、文件轮转,前端 JS 也能用。
安装
两端都要装:
cd src-tauri
cargo add tauri-plugin-log
npm install @tauri-apps/plugin-log
Rust 端注册插件:
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_log::Builder::new().build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
前端授权(src-tauri/capabilities/default.json):
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "主窗口权限",
"windows": ["main"],
"permissions": ["core:default", "log:default"]
}
在 JS 中写日志
装好后,前端可以直接调用:
import { trace, debug, info, warn, error } from "@tauri-apps/plugin-log";
trace("详细跟踪信息");
debug("调试信息");
info("一般信息");
warn("警告");
error("出错了");
五个级别从低到高:trace < debug < info < warn < error。你可以配置最高日志级别,低于它的会被丢弃。
在 Rust 中写日志
Rust 端用标准的 log crate 即可,plugin-log 会接管输出:
[dependencies]
log = "0.4"
log::info!("Tauri 太好用了!");
log::error!("出问题了:{}", reason);
把 console.log 转发到日志插件
前端的 console.log 默认不会进日志系统。如果你想统一管理,可以把 console 方法劫持一下:
import { trace, debug, info, warn, error } from "@tauri-apps/plugin-log";
function forwardConsole(
fnName: "log" | "debug" | "info" | "warn" | "error",
logger: (message: string) => Promise<void>
) {
const original = console[fnName];
console[fnName] = (message) => {
original(message);
logger(message);
};
}
forwardConsole("log", trace);
forwardConsole("debug", debug);
forwardConsole("info", info);
forwardConsole("warn", warn);
forwardConsole("error", error);
这样 console.log("hello") 会同时打印到浏览器控制台和日志插件。
日志输出目标(Targets)
plugin-log 的核心概念是 Target(输出目标)。你可以把日志发到终端、文件、WebView 控制台,或者同时发到多个地方。
输出到终端
use tauri_plugin_log::{Target, TargetKind};
tauri_plugin_log::Builder::new()
.target(Target::new(TargetKind::Stdout))
.build()
Stdout 是默认开启的,不写也有。Stderr 也行,换个管道而已。
输出到 WebView 控制台
想让 Rust 端的日志也显示在前端 DevTools 里?启用 Webview target:
tauri_plugin_log::Builder::new()
.target(Target::new(TargetKind::Webview))
.build()
然后在前端调用 attachConsole() 来接收:
import { attachConsole } from "@tauri-apps/plugin-log";
const detach = await attachConsole();
// 不想接收了就调用 detach()
持久化到文件
日志写文件最常用的是 LogDir,自动写到系统推荐的日志目录:
tauri_plugin_log::Builder::new()
.target(Target::new(TargetKind::LogDir {
file_name: Some("app".to_string()),
}))
.build()
各平台的日志目录:
| 平台 | 路径 |
|---|---|
| Windows | C:\Users\{用户}\AppData\Local\{bundleId}\logs |
| macOS | ~/Library/Logs/{bundleId} |
| Linux | ~/.local/share/{bundleId}/logs |
Tip默认日志文件达到大小上限会被丢弃。想保留旧文件,用
rotation_strategy设为KeepAll。调大小上限用max_file_size(单位字节)。
同时输出到多个目标
多个 Target 可以叠加:
use tauri_plugin_log::{Target, TargetKind};
tauri_plugin_log::Builder::new()
.targets([
Target::new(TargetKind::Stdout),
Target::new(TargetKind::LogDir { file_name: None }),
Target::new(TargetKind::Webview),
])
.build()
这样日志同时进终端、进文件、进前端控制台,三管齐下。
Note默认就是
Stdout+LogDir两个目标。想完全自定义、去掉默认的,调用.clear_targets()再加你自己的。
日志过滤与格式化
设置最高日志级别
tauri_plugin_log::Builder::new()
.level(log::LevelFilter::Info)
.build()
设成 Info 后,debug 和 trace 的日志会被丢弃。还可以按模块单独设级别:
tauri_plugin_log::Builder::new()
.level(log::LevelFilter::Info)
.level_for("my_crate::commands", log::LevelFilter::Trace)
.build()
这样大部分模块只记 Info 以上,但 commands 模块连 Trace 都记。
自定义过滤
用 filter 函数可以按 metadata 过滤,比如排除 hyper 的日志:
tauri_plugin_log::Builder::new()
.filter(|metadata| metadata.target() != "hyper")
.build()
自定义格式
默认格式是 DATE[TARGET][LEVEL] MESSAGE。想改:
tauri_plugin_log::Builder::new()
.format(|out, message, record| {
out.finish(format_args!(
"[{} {}] {}",
record.level(),
record.target(),
message
))
})
.build()
还可以给不同 Target 设不同格式,甚至改时区策略(默认 UTC,可切本地时区):
use tauri_plugin_log::TimezoneStrategy;
tauri_plugin_log::Builder::new()
.timezone_strategy(TimezoneStrategy::UseLocal)
.build()
小结
调试 Tauri 应用需要同时关注两端:Rust 端看终端输出(println! 或 plugin-log),前端看 WebView DevTools(右键检查或快捷键打开)。#[cfg(dev)] 和 #[cfg(debug_assertions)] 帮你区分开发和生产代码。日志插件 tauri-plugin-log 提供了完整的日志体系:五个级别(trace/debug/info/warn/error)、多种输出目标(Stdout/LogDir/Webview 可叠加)、按模块设级别、自定义格式和时区。前端 JS 和 Rust 都能写日志,统一管理,排查问题时不再两眼一抹黑。