Skip to content

Commit 1915563

Browse files
committed
debug: add early startup probe logging
1 parent bebe331 commit 1915563

5 files changed

Lines changed: 293 additions & 22 deletions

File tree

src-tauri/src/app/mod.rs

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,133 @@ use crate::commands;
1515
use components::tray;
1616

1717
pub fn run() {
18+
crate::core::logger::startup_probe::log("app::run: entered");
1819
let ctx = tauri::generate_context!();
20+
crate::core::logger::startup_probe::log("app::run: tauri context generated");
1921
let session_lock_manager = session_lock::SessionLockManager::new();
22+
crate::core::logger::startup_probe::log("app::run: session lock manager created");
2023

21-
let app = tauri::Builder::default()
24+
let builder = tauri::Builder::default()
2225
.manage(session_lock_manager.clone())
2326
.setup(move |app| {
24-
setup::register_plugins(app.handle());
27+
crate::core::logger::startup_probe::log("app::run setup: begin");
28+
setup::register_plugins(app.handle()).map_err(|error| {
29+
crate::core::logger::startup_probe::log_error(
30+
"app::run setup: register_plugins failed",
31+
error.to_string(),
32+
);
33+
anyhow::anyhow!("{}", error)
34+
})?;
35+
crate::core::logger::startup_probe::log("app::run setup: after register_plugins");
2536

2637
crate::infrastructure::persistence::tauri_store::ensure_store_loaded(app.handle())
27-
.map_err(|e| anyhow::anyhow!("{}", e))?;
38+
.map_err(|e| {
39+
crate::core::logger::startup_probe::log_error(
40+
"app::run setup: ensure_store_loaded failed",
41+
e.to_string(),
42+
);
43+
anyhow::anyhow!("{}", e)
44+
})?;
45+
crate::core::logger::startup_probe::log("app::run setup: after ensure_store_loaded");
2846
let log_dir =
2947
crate::infrastructure::persistence::tauri_store::get_logs_path(app.handle())
30-
.map_err(|e| anyhow::anyhow!("{}", e))?;
48+
.map_err(|e| {
49+
crate::core::logger::startup_probe::log_error(
50+
"app::run setup: get_logs_path failed",
51+
e.to_string(),
52+
);
53+
anyhow::anyhow!("{}", e)
54+
})?;
55+
crate::core::logger::startup_probe::log(format!(
56+
"app::run setup: resolved logs path={}",
57+
log_dir.display()
58+
));
3159
crate::core::logger::init_logging(&log_dir);
32-
setup::register_deep_link(app.handle().clone())?;
60+
crate::core::logger::startup_probe::log("app::run setup: after logger re-init");
61+
setup::register_deep_link(app.handle().clone()).map_err(|error| {
62+
crate::core::logger::startup_probe::log_error(
63+
"app::run setup: register_deep_link failed",
64+
error.to_string(),
65+
);
66+
error
67+
})?;
68+
crate::core::logger::startup_probe::log("app::run setup: after register_deep_link");
3369

34-
crate::commands::window::create_splashscreen_window(app.handle().clone())?;
70+
crate::commands::window::create_splashscreen_window(app.handle().clone()).map_err(
71+
|error| {
72+
crate::core::logger::startup_probe::log_error(
73+
"app::run setup: create_splashscreen_window failed",
74+
error.to_string(),
75+
);
76+
error
77+
},
78+
)?;
79+
crate::core::logger::startup_probe::log(
80+
"app::run setup: after create_splashscreen_window",
81+
);
3582

36-
tray::menu(app)?;
83+
tray::menu(app).map_err(|error| {
84+
crate::core::logger::startup_probe::log_error(
85+
"app::run setup: tray::menu failed",
86+
error.to_string(),
87+
);
88+
error
89+
})?;
90+
crate::core::logger::startup_probe::log("app::run setup: after tray::menu");
3791

3892
// 初始化依赖 Tauri 的组件
39-
lifecycle::init_tauri_dependent(app.handle())?;
93+
lifecycle::init_tauri_dependent(app.handle()).map_err(|error| {
94+
crate::core::logger::startup_probe::log_error(
95+
"app::run setup: init_tauri_dependent failed",
96+
error.to_string(),
97+
);
98+
error
99+
})?;
100+
crate::core::logger::startup_probe::log(
101+
"app::run setup: after lifecycle::init_tauri_dependent",
102+
);
40103

41104
setup::init_simprint_runtime_background(app.handle().clone());
105+
crate::core::logger::startup_probe::log(
106+
"app::run setup: after init_simprint_runtime_background",
107+
);
42108

43109
// 初始化会话自动锁定后台任务
44110
session_lock::init_session_lock_background(
45111
app.handle().clone(),
46112
session_lock_manager.clone(),
47113
);
114+
crate::core::logger::startup_probe::log(
115+
"app::run setup: after init_session_lock_background",
116+
);
48117

49118
// 初始化应用启动流程(显示 splashscreen)
50119
splashscreen::init_startup(app.handle().clone());
120+
crate::core::logger::startup_probe::log(
121+
"app::run setup: after splashscreen::init_startup",
122+
);
123+
crate::core::logger::startup_probe::log("app::run setup: completed");
51124

52125
Ok(())
53126
})
54127
.invoke_handler(commands::register_handles())
55-
.on_window_event(events::window_event_handle)
56-
.build(ctx)
57-
.expect("error while building application");
128+
.on_window_event(events::window_event_handle);
129+
130+
crate::core::logger::startup_probe::log("app::run: before builder.build(ctx)");
131+
let app = match builder.build(ctx) {
132+
Ok(app) => {
133+
crate::core::logger::startup_probe::log("app::run: after builder.build(ctx)");
134+
app
135+
}
136+
Err(error) => {
137+
crate::core::logger::startup_probe::log_error(
138+
"app::run: builder.build(ctx) failed",
139+
error.to_string(),
140+
);
141+
panic!("error while building application: {}", error);
142+
}
143+
};
58144

145+
crate::core::logger::startup_probe::log("app::run: before app.run");
59146
app.run(events::run_event_handle);
60147
}

src-tauri/src/app/setup.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use tauri::{AppHandle, Emitter};
33
use tauri_plugin_autostart::MacosLauncher;
44

55
/// 注册插件
6-
pub fn register_plugins(app_handle: &AppHandle) {
6+
pub fn register_plugins(app_handle: &AppHandle) -> anyhow::Result<()> {
7+
crate::core::logger::startup_probe::log("setup::register_plugins: begin");
8+
79
// Register the single instance plugin
810
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
911
#[cfg(feature = "production")]
@@ -27,27 +29,51 @@ pub fn register_plugins(app_handle: &AppHandle) {
2729
let _ = main_window.set_focus();
2830
}
2931
}))
30-
.unwrap();
32+
.map_err(|error| anyhow::anyhow!("single_instance plugin init failed: {}", error))?;
33+
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
34+
#[cfg(feature = "production")]
35+
crate::core::logger::startup_probe::log("setup::register_plugins: single_instance ok");
3136

3237
// Register process plugin
33-
app_handle.plugin(tauri_plugin_process::init()).unwrap();
38+
app_handle
39+
.plugin(tauri_plugin_process::init())
40+
.map_err(|error| anyhow::anyhow!("process plugin init failed: {}", error))?;
41+
crate::core::logger::startup_probe::log("setup::register_plugins: process ok");
3442

35-
app_handle.plugin(tauri_plugin_upload::init()).unwrap();
43+
app_handle
44+
.plugin(tauri_plugin_upload::init())
45+
.map_err(|error| anyhow::anyhow!("upload plugin init failed: {}", error))?;
46+
crate::core::logger::startup_probe::log("setup::register_plugins: upload ok");
3647

3748
// deep-link 插件
38-
app_handle.plugin(tauri_plugin_deep_link::init()).unwrap();
49+
app_handle
50+
.plugin(tauri_plugin_deep_link::init())
51+
.map_err(|error| anyhow::anyhow!("deep_link plugin init failed: {}", error))?;
52+
crate::core::logger::startup_probe::log("setup::register_plugins: deep_link ok");
3953

4054
// opener 插件
41-
app_handle.plugin(tauri_plugin_opener::init()).unwrap();
55+
app_handle
56+
.plugin(tauri_plugin_opener::init())
57+
.map_err(|error| anyhow::anyhow!("opener plugin init failed: {}", error))?;
58+
crate::core::logger::startup_probe::log("setup::register_plugins: opener ok");
4259

4360
// dialog 插件
44-
app_handle.plugin(tauri_plugin_dialog::init()).unwrap();
61+
app_handle
62+
.plugin(tauri_plugin_dialog::init())
63+
.map_err(|error| anyhow::anyhow!("dialog plugin init failed: {}", error))?;
64+
crate::core::logger::startup_probe::log("setup::register_plugins: dialog ok");
4565

4666
// store 插件
47-
app_handle.plugin(tauri_plugin_store::Builder::new().build()).unwrap();
67+
app_handle
68+
.plugin(tauri_plugin_store::Builder::new().build())
69+
.map_err(|error| anyhow::anyhow!("store plugin init failed: {}", error))?;
70+
crate::core::logger::startup_probe::log("setup::register_plugins: store ok");
4871

4972
// clipboard_manager
50-
app_handle.plugin(tauri_plugin_clipboard_manager::init()).unwrap();
73+
app_handle
74+
.plugin(tauri_plugin_clipboard_manager::init())
75+
.map_err(|error| anyhow::anyhow!("clipboard_manager plugin init failed: {}", error))?;
76+
crate::core::logger::startup_probe::log("setup::register_plugins: clipboard_manager ok");
5177

5278
// 自动启动插件
5379
#[cfg(desktop)]
@@ -56,17 +82,24 @@ pub fn register_plugins(app_handle: &AppHandle) {
5682
MacosLauncher::LaunchAgent,
5783
Some(vec![]), /* 传递给应用程序的任意数量的参数 */
5884
))
59-
.unwrap();
85+
.map_err(|error| anyhow::anyhow!("autostart plugin init failed: {}", error))?;
86+
#[cfg(desktop)]
87+
crate::core::logger::startup_probe::log("setup::register_plugins: autostart ok");
88+
89+
crate::core::logger::startup_probe::log("setup::register_plugins: completed");
90+
Ok(())
6091
}
6192

6293
/// 注册深度链接
6394
#[allow(dead_code)]
6495
pub fn register_deep_link(app: AppHandle) -> Result<(), anyhow::Error> {
96+
crate::core::logger::startup_probe::log("setup::register_deep_link: begin");
6597
#[cfg(any(windows, target_os = "linux"))]
6698
{
6799
use tauri_plugin_deep_link::DeepLinkExt;
68100
app.deep_link().register_all()?;
69101
};
102+
crate::core::logger::startup_probe::log("setup::register_deep_link: completed");
70103
Ok(())
71104
}
72105

@@ -89,15 +122,26 @@ pub fn init_server_public_key_background(app_handle: AppHandle) {
89122
}
90123

91124
pub fn init_simprint_runtime_background(app_handle: AppHandle) {
125+
crate::core::logger::startup_probe::log("setup::init_simprint_runtime_background: spawn");
92126
tauri::async_runtime::spawn(async move {
93127
use crate::app::context::AppContext;
94128

129+
crate::core::logger::startup_probe::log(
130+
"setup::init_simprint_runtime_background: task begin",
131+
);
95132
let ctx = AppContext::get();
96133
ctx.simprint_runtime_manager.set_app_handle(app_handle.clone()).await;
97134
ctx.runtime_update_service.start_background(app_handle.clone());
98135

99136
if let Err(error) = ctx.simprint_runtime_manager.start_background().await {
137+
crate::core::logger::startup_probe::log_error(
138+
"setup::init_simprint_runtime_background: start_background failed",
139+
error.to_string(),
140+
);
100141
log::warn!("failed to start simprint-runtime: {}", error);
101142
}
143+
crate::core::logger::startup_probe::log(
144+
"setup::init_simprint_runtime_background: task completed",
145+
);
102146
});
103147
}

src-tauri/src/core/logger/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
1010
mod channels;
1111
pub mod modules;
12+
pub mod startup_probe;
1213
mod writer;
1314

1415
pub use channels::{Channel, file_stem_for_target, log_path_for_target};
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use std::fs::{self, OpenOptions};
2+
use std::io::Write;
3+
use std::path::{Path, PathBuf};
4+
use std::sync::OnceLock;
5+
use std::time::{SystemTime, UNIX_EPOCH};
6+
7+
static STARTUP_PROBE_PATH: OnceLock<PathBuf> = OnceLock::new();
8+
9+
const STARTUP_PROBE_FILENAME: &str = "simprint-startup-probe.log";
10+
11+
pub fn log(message: impl AsRef<str>) {
12+
append("INFO", message.as_ref());
13+
}
14+
15+
pub fn log_error(stage: &str, error: impl AsRef<str>) {
16+
append("ERROR", &format!("{}: {}", stage, error.as_ref()));
17+
}
18+
19+
pub fn log_panic(panic_info: &std::panic::PanicHookInfo) {
20+
let location = panic_info
21+
.location()
22+
.map(|location| format!("{}:{}", location.file(), location.line()))
23+
.unwrap_or_else(|| "unknown".to_string());
24+
let message = if let Some(message) = panic_info.payload().downcast_ref::<String>() {
25+
message.as_str()
26+
} else if let Some(message) = panic_info.payload().downcast_ref::<&str>() {
27+
message
28+
} else {
29+
"unknown panic payload"
30+
};
31+
32+
append("PANIC", &format!("at {}: {}", location, message));
33+
}
34+
35+
pub fn current_path() -> Option<&'static Path> {
36+
STARTUP_PROBE_PATH.get().map(PathBuf::as_path)
37+
}
38+
39+
fn append(level: &str, message: &str) {
40+
let line = format!(
41+
"[{}][pid:{}][{}] {}\n",
42+
unix_timestamp_millis(),
43+
std::process::id(),
44+
level,
45+
message
46+
);
47+
48+
if let Some(path) = STARTUP_PROBE_PATH.get() {
49+
if try_append(path, &line).is_ok() {
50+
return;
51+
}
52+
}
53+
54+
for candidate in candidate_paths() {
55+
if try_append(&candidate, &line).is_ok() {
56+
let _ = STARTUP_PROBE_PATH.set(candidate);
57+
return;
58+
}
59+
}
60+
}
61+
62+
fn candidate_paths() -> Vec<PathBuf> {
63+
let mut paths = Vec::new();
64+
65+
if let Ok(dir) = crate::core::paths::PathManager::get_bootstrap_logs_dir() {
66+
paths.push(dir.join(STARTUP_PROBE_FILENAME));
67+
}
68+
69+
paths.push(std::env::temp_dir().join(STARTUP_PROBE_FILENAME));
70+
71+
if let Ok(cwd) = std::env::current_dir() {
72+
paths.push(cwd.join(STARTUP_PROBE_FILENAME));
73+
}
74+
75+
paths
76+
}
77+
78+
fn try_append(path: &Path, line: &str) -> std::io::Result<()> {
79+
if let Some(parent) = path.parent() {
80+
fs::create_dir_all(parent)?;
81+
}
82+
83+
let mut file = OpenOptions::new().create(true).append(true).open(path)?;
84+
file.write_all(line.as_bytes())?;
85+
file.flush()?;
86+
Ok(())
87+
}
88+
89+
fn unix_timestamp_millis() -> u128 {
90+
SystemTime::now()
91+
.duration_since(UNIX_EPOCH)
92+
.map(|duration| duration.as_millis())
93+
.unwrap_or(0)
94+
}

0 commit comments

Comments
 (0)