Skip to main content

Mountain/IPC/DevLog/
mod.rs

1
2//! # DevLog - Tag-filtered development logging
3//!
4//! Tag-gated logging used across Mountain. Controlled by the
5//! `Trace` env var: `Trace=vfs,ipc` for selective tags,
6//! `Trace=all` for everything, `Trace=short` for the
7//! everything-but-firehose preset (path aliasing + dedupe).
8//! Mirror to a session log file when `Record=1` (or when
9//! `Trace` is set in a debug build).
10//!
11//! Layout: every public Fn/Struct lives in its own sibling
12//! file. The two macros (`dev_log!`, `otel_span!`) live here
13//! so `#[macro_export]` puts them at the crate root and the
14//! callsite spelling stays `dev_log!("ipc", "…")`.
15
16pub mod AliasPath;
17
18pub mod AppDataPrefix;
19
20pub mod DebugOnce;
21
22pub mod DedupState;
23
24pub mod EmitOTLPSpan;
25
26pub mod FlushDedup;
27
28pub mod InitEager;
29
30pub mod IsBenignEnoent;
31
32pub mod IsEnabled;
33
34pub mod IsShort;
35
36pub mod NowNano;
37
38pub mod SessionTimestamp;
39
40pub mod WriteToFile;
41
42/// Tag-gated dev log. Compiled out in release builds.
43///
44/// Under `Trace=short` aliases the long Tauri app-data prefix
45/// to `$APP` and collapses consecutive duplicates with a
46/// `(xN)` tail. The body is fully gated on
47/// `cfg!(debug_assertions)` so release builds get zero runtime
48/// cost (LLVM dead-codes the format / IsEnabled / file-sink
49/// path).
50#[macro_export]
51macro_rules! dev_log {
52
53	($Tag:expr, $($Arg:tt)*) => {
54
55		if cfg!(debug_assertions) && $crate::IPC::DevLog::IsEnabled::Fn($Tag) {
56
57			let RawMessage = format!($($Arg)*);
58
59			let TagUpper = $Tag.to_uppercase();
60
61			if $crate::IPC::DevLog::IsShort::Fn() {
62
63				let Aliased = $crate::IPC::DevLog::AliasPath::Fn(&RawMessage);
64
65				let Key = format!("{}:{}", TagUpper, Aliased);
66
67				let ShouldPrint = {
68
69					if let Ok(mut State) = $crate::IPC::DevLog::DedupState::DEDUP.lock() {
70
71						if State.LastKey == Key {
72
73							State.Count += 1;
74
75							false
76						} else {
77
78							let PrevCount = State.Count;
79
80							let HadPrev = !State.LastKey.is_empty();
81
82							State.LastKey = Key;
83
84							State.Count = 1;
85
86							if HadPrev && PrevCount > 1 {
87
88								let Tail = format!("  (x{})", PrevCount);
89
90								eprintln!("{}", Tail);
91
92								$crate::IPC::DevLog::WriteToFile::Fn(&Tail);
93							}
94
95							true
96						}
97					} else {
98
99						true
100					}
101				};
102
103				if ShouldPrint {
104
105					let Formatted = format!("[DEV:{}] {}", TagUpper, Aliased);
106
107					eprintln!("{}", Formatted);
108
109					$crate::IPC::DevLog::WriteToFile::Fn(&Formatted);
110				}
111			} else {
112
113				let Formatted = format!("[DEV:{}] {}", TagUpper, RawMessage);
114
115				eprintln!("{}", Formatted);
116
117				$crate::IPC::DevLog::WriteToFile::Fn(&Formatted);
118			}
119		}
120	};
121}
122
123/// Convenience macro: emit an OTLP span for an IPC handler.
124/// Usage: `otel_span!("file:readFile", StartNano, &[("path", &Path)]);`
125#[macro_export]
126macro_rules! otel_span {
127	($Name:expr, $Start:expr, $Attrs:expr) => {
128		$crate::IPC::DevLog::EmitOTLPSpan::Fn($Name, $Start, $crate::IPC::DevLog::NowNano::Fn(), $Attrs)
129	};
130
131	($Name:expr, $Start:expr) => {
132		$crate::IPC::DevLog::EmitOTLPSpan::Fn($Name, $Start, $crate::IPC::DevLog::NowNano::Fn(), &[])
133	};
134}