Skip to main content

Mountain/Binary/Build/
LoggingPlugin.rs

1//! # Logging Plugin Module
2//!
3//! Configures and creates the Tauri logging plugin with appropriate targets and
4//! filters.
5
6use log::LevelFilter;
7use tauri::plugin::TauriPlugin;
8use tauri_plugin_log::{RotationStrategy, Target, TargetKind, TimezoneStrategy};
9
10use crate::IPC::DevLog;
11
12/// Compress a Rust module target path to its final segment.
13///
14/// `D::Binary::Main::Entry` → `Entry`
15/// `D::Environment::StorageProvider` → `StorageProvider`
16fn CompressTarget(Target:&str) -> &str { Target.rsplit("::").next().unwrap_or(Target) }
17
18/// Creates and configures the logging plugin with multi-target output and level
19/// filtering.
20///
21/// # Arguments
22///
23/// * `LogLevel` - The desired log level (Trace, Debug, Info, Warn, Error)
24///
25/// # Returns
26///
27/// A configured `tauri_plugin_log::TauriPlugin` instance.
28///
29/// # Logging Strategy
30///
31/// - Release default: Info (low noise) unless RUST_LOG overrides
32/// - Debug default: Debug (high fidelity) unless RUST_LOG overrides
33/// - Very noisy dependencies are capped using level_for(...) and filter(...)
34///
35/// # Short Mode
36///
37/// When `Trace=short`:
38/// - Module targets compressed to last segment
39/// - Long app-data paths aliased to `$APP`
40/// - Storage key-by-key logs suppressed (batch count only)
41///
42/// # Targets
43///
44/// - Stdout: Console output for development/terminal viewing
45/// - LogDir: Persistent log file (Mountain.log) in the app's log directory
46/// - Webview: Logs sent to the webview console for frontend debugging
47///
48/// # Noise Filtering
49///
50/// The following noisy dependencies are capped at Info level regardless of
51/// RUST_LOG:
52/// - hyper: HTTP library verbose logs
53/// - mio: Async I/O polling logs
54/// - tao: Windowing system logs
55/// - tracing: Structured logging internal logs
56///
57/// Additionally, the following targets are filtered out entirely:
58/// - polling: File watcher events (very noisy)
59/// - tokio_reactor: Async reactor events
60/// - want: Connection readiness logs
61pub fn LoggingPlugin<R:tauri::Runtime>(LogLevel:LevelFilter) -> TauriPlugin<R> {
62	tauri_plugin_log::Builder::new()
63
64		// Configure output targets
65		.targets([
66			Target::new(TargetKind::Stdout),
67
68			Target::new(TargetKind::LogDir {
69				file_name: Some("Mountain.log".into()),
70			}),
71
72			Target::new(TargetKind::Webview),
73		])
74
75		// Configure file rotation and timezone
76		.timezone_strategy(TimezoneStrategy::UseLocal)
77		.rotation_strategy(RotationStrategy::KeepAll)
78
79		// Set base log level
80		.level(LogLevel)
81
82		// Cap very noisy dependencies at Info level
83		.level_for("hyper", LevelFilter::Info)
84		.level_for("mio", LevelFilter::Info)
85		.level_for("tao", LevelFilter::Info)
86		.level_for("tracing", LevelFilter::Info)
87
88		// `ignore` and `globset` (used by Mountain's extension scanner +
89		// `WorkspaceProvider::FindFiles` walk) emit a DEBUG line per
90		// `.gitignore` opened, per glob compiled, and per file
91		// whitelisted/ignored. A single `debug-electron-bundled` boot
92		// produces tens of thousands of these lines, drowning out every
93		// extension activation / SCM register / GIT-MARK / IPC trace
94		// the rest of Mountain emits at the same level. Cap to Warn so
95		// the extension-activation signal is readable.
96		.level_for("ignore", LevelFilter::Warn)
97		.level_for("ignore::walk", LevelFilter::Warn)
98		.level_for("ignore::gitignore", LevelFilter::Warn)
99		.level_for("globset", LevelFilter::Warn)
100
101		// `keyring` (used by Mountain's secret-storage path on the
102		// `dev1phpTools.license.data` lookup chain) emits a 3-line
103		// DEBUG block per `get_password` call - "creating entry",
104		// "created entry", "get password from entry" - per refresh
105		// tick. After the workbench paints these fire indefinitely.
106		// Cap to Warn alongside the other dependency mutes.
107		.level_for("keyring", LevelFilter::Warn)
108
109		// Filter out extremely noisy targets
110		.filter(|Metadata| {
111			!Metadata.target().starts_with("polling")
112				&& !Metadata.target().starts_with("tokio_reactor")
113				&& !Metadata.target().starts_with("want")
114		})
115
116		// Format logs with category-like structure: [LEVEL] [TARGET] message
117		.format(|out, message, record| {
118			if DevLog::IsShort::Fn() {
119				let ShortTarget = CompressTarget(record.target());
120				let RawMessage = format!("{}", message);
121				let Aliased = DevLog::AliasPath::Fn(&RawMessage);
122				out.finish(format_args!(
123					"[{:<5}] [{}] {}",
124
125					record.level(),
126
127					ShortTarget,
128
129					Aliased
130				))
131			} else {
132				out.finish(format_args!(
133					"[{:<5}] [{}] {}",
134
135					record.level(),
136
137					record.target(),
138
139					message
140				))
141			}
142		})
143		.build()
144}