Skip to content

Commit fbeb0e5

Browse files
feat(desktop): file-based logs with rotation (hoppscotch#5009)
This PR adds a file-based logging system with size-based rotation to the desktop application. It essentially redirects existing diagnostic to size-based rotating files for troubleshooting environment-specific issues. Closes HFE-801 The desktop application currently lacks a persistent logging mechanism in production environments. Logs are only available through the development mode console. This PR will help diagnose issues reported in hoppscotch#4859, hoppscotch#4950, hoppscotch#5003, discussions hoppscotch#4984 and hoppscotch#4986. Mainly aiming to understand errors in specific environments that can't be reproduced in our testing setups. This implementation uses the tracing ecosystem (`tracing`, `tracing_subscriber`, `tracing_appender`) along with `file_rotate` to create log files in the platform's log directory. The logs are automatically rotated when they reach `10MB`, with a maximum of `5` files retained. Thinking 10 * 5 MB is reasonable disk usage while maintaining sufficient history. The system currently writes to both the console (with ANSI colors where supported) and to files (without ANSI formatting for readability). Log levels are currently controlled via the `RUST_LOG` environment variable, defaulting to "debug" when not specified. | OS | Log File Path | |---------|------------------------------------------------------| | Windows | `C:\Users\<username>\AppData\Local\io.hoppscotch.desktop\logs\io.hoppscotch.desktop.log` | | macOS | `~/Library/Logs/io.hoppscotch.desktop/io.hoppscotch.desktop.log` | | Linux | `~/.local/share/io.hoppscotch.desktop/logs/io.hoppscotch.desktop.log` |
1 parent 13b46d5 commit fbeb0e5

File tree

5 files changed

+111
-105
lines changed

5 files changed

+111
-105
lines changed

packages/hoppscotch-desktop/src-tauri/Cargo.lock

Lines changed: 41 additions & 91 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/hoppscotch-desktop/src-tauri/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ serde = { version = "1", features = ["derive"] }
2424
serde_json = { version = "1", features = [] }
2525
tracing = "0.1.41"
2626
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
27+
tracing-appender = { version = "0.2.3" }
2728
tauri-plugin-store = "2.2.0"
2829
tauri-plugin-dialog = "2.2.0"
2930
tauri-plugin-fs = "2.2.0"
@@ -35,6 +36,7 @@ tower-http = { version = "0.6.2", features = ["cors"] }
3536
portpicker = "0.1.1"
3637
tokio = "1.43.0"
3738
tauri-plugin-process = "2.2.0"
39+
file-rotate = "0.8.0"
3840

3941
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
4042
tauri-plugin-updater = "2.3.1"

packages/hoppscotch-desktop/src-tauri/src/lib.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod logger;
12
pub mod server;
23
pub mod updater;
34

@@ -19,6 +20,12 @@ fn hopp_auth_port() -> u16 {
1920
pub fn run() {
2021
tracing::info!("Starting Hoppscotch Desktop v{}", env!("CARGO_PKG_VERSION"));
2122

23+
let server_port = portpicker::pick_unused_port().expect("Cannot find unused port");
24+
SERVER_PORT
25+
.set(server_port)
26+
.expect("Failed to set server port");
27+
tracing::info!("Selected server port: {}", server_port);
28+
2229
tauri::Builder::default()
2330
.plugin(
2431
tauri_plugin_window_state::Builder::new()
@@ -61,14 +68,20 @@ pub fn run() {
6168
})
6269
.setup(|app| {
6370
let handle = app.handle().clone();
64-
let port = portpicker::pick_unused_port().expect("Cannot find unused port");
65-
SERVER_PORT.set(port).expect("Failed to set server port");
71+
72+
let port = *SERVER_PORT.get().expect("Server port not initialized");
73+
tracing::info!(port = port, "Initializing server with pre-selected port");
6674
let port = server::init(port, handle);
6775
tracing::info!(port = port, "Server initialization complete");
6876
Ok(())
6977
})
7078
.plugin(tauri_plugin_shell::init())
7179
.plugin(tauri_plugin_fs::init())
80+
.setup(|app| {
81+
logger::setup(app.handle().clone())?;
82+
tracing::info!("Logger setup complete");
83+
Ok(())
84+
})
7285
.plugin(tauri_plugin_appload::init(
7386
VendorConfigBuilder::new().bundle(
7487
include_bytes!("../../bundle.zip").to_vec(),
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate};
2+
use tauri::{AppHandle, Manager, Runtime};
3+
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
4+
5+
pub struct LogGuard(pub tracing_appender::non_blocking::WorkerGuard);
6+
7+
pub fn setup<R: Runtime>(app_handle: AppHandle<R>) -> Result<(), Box<dyn std::error::Error>> {
8+
let log_dir = app_handle.path().app_log_dir()?;
9+
std::fs::create_dir_all(&log_dir)?;
10+
11+
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| format!("debug").into());
12+
13+
let log_file_path = log_dir.join("io.hoppscotch.desktop.log");
14+
tracing::info!(log_file_path =? &log_file_path);
15+
16+
let file = FileRotate::new(
17+
&log_file_path,
18+
AppendCount::new(5),
19+
ContentLimit::Bytes(10 * 1024 * 1024),
20+
Compression::None,
21+
None,
22+
);
23+
24+
let (non_blocking, guard) = tracing_appender::non_blocking(file);
25+
26+
let console_layer = fmt::layer()
27+
.with_writer(std::io::stdout)
28+
.with_thread_ids(true)
29+
.with_thread_names(true)
30+
.with_ansi(!cfg!(target_os = "windows"));
31+
32+
let file_layer = fmt::layer()
33+
.with_writer(non_blocking)
34+
.with_ansi(false)
35+
.with_thread_ids(true)
36+
.with_thread_names(true);
37+
38+
tracing_subscriber::registry()
39+
.with(env_filter)
40+
.with(file_layer)
41+
.with(console_layer)
42+
.init();
43+
44+
app_handle.manage(LogGuard(guard));
45+
46+
tracing::info!(
47+
log_file = %log_file_path.display(),
48+
"Logging initialized with single file"
49+
);
50+
51+
Ok(())
52+
}

0 commit comments

Comments
 (0)