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 // Configure output targets
64 .targets([
65 Target::new(TargetKind::Stdout),
66
67 Target::new(TargetKind::LogDir {
68 file_name: Some("Mountain.log".into()),
69 }),
70
71 Target::new(TargetKind::Webview),
72 ])
73 // Configure file rotation and timezone
74 .timezone_strategy(TimezoneStrategy::UseLocal)
75 .rotation_strategy(RotationStrategy::KeepAll)
76 // Set base log level
77 .level(LogLevel)
78 // Cap very noisy dependencies at Info level
79 .level_for("hyper", LevelFilter::Info)
80 .level_for("mio", LevelFilter::Info)
81 .level_for("tao", LevelFilter::Info)
82 .level_for("tracing", LevelFilter::Info)
83 // `ignore` and `globset` (used by Mountain's extension scanner +
84 // `WorkspaceProvider::FindFiles` walk) emit a DEBUG line per
85 // `.gitignore` opened, per glob compiled, and per file
86 // whitelisted/ignored. A single `debug-electron-bundled` boot
87 // produces tens of thousands of these lines, drowning out every
88 // extension activation / SCM register / GIT-MARK / IPC trace
89 // the rest of Mountain emits at the same level. Cap to Warn so
90 // the extension-activation signal is readable.
91 .level_for("ignore", LevelFilter::Warn)
92 .level_for("ignore::walk", LevelFilter::Warn)
93 .level_for("ignore::gitignore", LevelFilter::Warn)
94 .level_for("globset", LevelFilter::Warn)
95 // `keyring` (used by Mountain's secret-storage path on the
96 // `dev1phpTools.license.data` lookup chain) emits a 3-line
97 // DEBUG block per `get_password` call - "creating entry",
98 // "created entry", "get password from entry" - per refresh
99 // tick. After the workbench paints these fire indefinitely.
100 // Cap to Warn alongside the other dependency mutes.
101 .level_for("keyring", LevelFilter::Warn)
102 // Filter out extremely noisy targets
103 .filter(|Metadata| {
104 !Metadata.target().starts_with("polling")
105 && !Metadata.target().starts_with("tokio_reactor")
106 && !Metadata.target().starts_with("want")
107 })
108 // Format logs with category-like structure: [LEVEL] [TARGET] message
109 .format(|out, message, record| {
110 if DevLog::IsShort::Fn() {
111 let ShortTarget = CompressTarget(record.target());
112 let RawMessage = format!("{}", message);
113 let Aliased = DevLog::AliasPath::Fn(&RawMessage);
114 out.finish(format_args!(
115 "[{:<5}] [{}] {}",
116
117 record.level(),
118
119 ShortTarget,
120
121 Aliased
122 ))
123 } else {
124 out.finish(format_args!(
125 "[{:<5}] [{}] {}",
126
127 record.level(),
128
129 record.target(),
130
131 message
132 ))
133 }
134 })
135 .build()
136}