mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-06 17:38:06 +00:00
feat(observability): add centralized diagnostics logging engine and native log viewer panel
- Configure tauri-plugin-log with 10MB rotation and 3-file retention - Add high-frequency format filter to strip [download]% progress ticks - Hook yt-dlp, aria2c, and native reqwest runners with lifecycle log macros - Add export_logs Tauri command for async log file export via save dialog - Create DiagnosticsView React component with streaming monospace console - Apply severity highlighting: ERROR=red, WARN=yellow, INFO=grey, DEBUG=dim - Wire Diagnostics tab into sidebar navigation and ActiveView routing - Log native download failures to log::error! in download.rs
This commit is contained in:
@@ -189,7 +189,7 @@ impl CoordinatorEventSink {
|
||||
fn emit_failed(&self, id: Uuid, error: String) {
|
||||
match self {
|
||||
Self::Tauri(app_handle) => {
|
||||
eprintln!("download {id} failed: {error}");
|
||||
log::error!("native download {} failed: {}", id, error);
|
||||
let _ = app_handle.emit("download-failed", id.to_string());
|
||||
}
|
||||
Self::Headless(event_tx) => {
|
||||
|
||||
@@ -154,6 +154,7 @@ pub enum ActiveView {
|
||||
Scheduler,
|
||||
#[serde(rename = "speedLimiter")]
|
||||
SpeedLimiter,
|
||||
Diagnostics,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, TS)]
|
||||
|
||||
+34
-1
@@ -1301,6 +1301,29 @@ fn delete_file(app_handle: tauri::AppHandle, path: String) -> Result<(), String>
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn export_logs(app_handle: tauri::AppHandle, dest_path: String) -> Result<String, String> {
|
||||
use tauri::Manager;
|
||||
let log_dir = app_handle.path().app_log_dir().map_err(|e| e.to_string())?;
|
||||
let log_file = log_dir.join("firelink.log");
|
||||
let src = if log_file.exists() {
|
||||
log_file
|
||||
} else {
|
||||
let mut found = None;
|
||||
if let Ok(mut entries) = tokio::fs::read_dir(&log_dir).await {
|
||||
while let Ok(Some(entry)) = entries.next_entry().await {
|
||||
if entry.path().extension().is_some_and(|e| e == "log") {
|
||||
found = Some(entry.path());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
found.ok_or_else(|| "No log file found in app log directory".to_string())?
|
||||
};
|
||||
tokio::fs::copy(&src, &dest_path).await.map_err(|e| e.to_string())?;
|
||||
Ok(dest_path)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn toggle_tray_icon(app_handle: tauri::AppHandle, show: bool) -> Result<(), String> {
|
||||
use tauri::tray::TrayIconBuilder;
|
||||
@@ -1785,6 +1808,15 @@ pub fn run() {
|
||||
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Webview),
|
||||
])
|
||||
.level(if cfg!(debug_assertions) { log::LevelFilter::Debug } else { log::LevelFilter::Info })
|
||||
.max_file_size(10_000_000)
|
||||
.rotation_strategy(tauri_plugin_log::RotationStrategy::KeepSome(3))
|
||||
.format(move |out, message, _record| {
|
||||
let msg = message.to_string();
|
||||
if msg.contains("[download]") && msg.contains('%') {
|
||||
return;
|
||||
}
|
||||
out.finish(format_args!("{}\n", msg));
|
||||
})
|
||||
.build(),
|
||||
)
|
||||
.plugin(tauri_plugin_store::Builder::new().build())
|
||||
@@ -1811,7 +1843,8 @@ pub fn run() {
|
||||
enqueue_download, enqueue_many, move_in_queue, remove_from_queue, get_pending_order,
|
||||
commands::reveal_in_file_manager, commands::open_downloaded_file, commands::trash_download_assets,
|
||||
parity::get_system_proxy, parity::get_file_category, parity::check_for_updates, parity::is_supported_media, parity::get_supported_media_domains,
|
||||
parity::create_category_directories
|
||||
parity::create_category_directories,
|
||||
export_logs
|
||||
])
|
||||
.build(tauri::generate_context!())
|
||||
.expect("error while building tauri application")
|
||||
|
||||
Reference in New Issue
Block a user