Skip to main content

Mountain/IPC/DevLog/
mod.rs

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