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}