Skip to content

Commit f7625f3

Browse files
feat(Mountain): Add RenderDevLog command and diagnostic logging tags
Add a new Tauri command `RenderDevLog` that bridges TypeScript-side tagged logs (Wind/Sky/Cocoon) into Mountain's `dev_log!` file sink. This enables a single `Mountain.dev.log` to carry the complete tag-filterable picture of a session, rather than requiring cross-referencing between browser console and log file. Also add five new diagnostic tags to isolate architectural gaps during debugging: - `notif-drop`: Notifications hitting the default arm (no handler) - `provider-register`: Accepted register_*_provider notifications with extension IDs - `channel-stub`: Wind/Output TauriMainProcessService.call stub hits vs route vs miss - `git`: localGit channel, GitExec RPC, SCM provider group updates - `tree-view`: tree.register, GetTreeChildren, sky://tree-view/create events Apply tags across SCM.rs, TreeView.rs, CreateEffectForRequest/TreeView.rs, and MountainVinegRPCService.rs to provide visibility into extension host integration issues. Impact: Developers can now filter `LAND_DEV_LOG=git,tree-view` to isolate specific subsystem issues, and TS-originated logs appear in the same file with `[RenderDevLog]` prefix for grep separation.
1 parent 85bd2a4 commit f7625f3

8 files changed

Lines changed: 137 additions & 0 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//! # RenderDevLogCommand
2+
//!
3+
//! Bridges TypeScript-side tagged logs (Wind / Sky / Cocoon running in the
4+
//! WebView) into Mountain's `dev_log!` file sink so a single
5+
//! `Mountain.dev.log` carries the complete tag-filterable picture of a
6+
//! session, not just the Rust portion.
7+
//!
8+
//! ## Why
9+
//!
10+
//! Wind's `Function/DevLog.ts` prints to `console.log`, visible only in
11+
//! DevTools. Mountain's `dev_log!` writes to a timestamped
12+
//! `Mountain.dev.log` with `LAND_DEV_LOG` tag filtering. The two observe
13+
//! the same boot but the outputs live in two places - reviewing a session
14+
//! means cross-referencing browser console + tail-f on the file. This
15+
//! command lets any TS caller mirror a tagged line into the file sink so
16+
//! `LAND_DEV_LOG=channel-stub,git tail -f Mountain.dev.log` captures both
17+
//! sides filtered identically.
18+
//!
19+
//! ## Contract
20+
//!
21+
//! - `Tag` is matched against `LAND_DEV_LOG` exactly as Rust tags are;
22+
//! disabled tags produce no output (cheap no-op on the Mountain side).
23+
//! - `Message` is the fully-formatted log string - the caller has
24+
//! already done any interpolation.
25+
//! - The command is fire-and-forget from the renderer's perspective
26+
//! (returns `()` immediately); failures to write are swallowed.
27+
//! - Prefix `[RenderDevLog]` is added so grep can always separate
28+
//! TS-originated lines from native `dev_log!` entries that share the
29+
//! same tag.
30+
31+
#![allow(non_snake_case)]
32+
33+
use crate::dev_log;
34+
35+
#[tauri::command]
36+
pub fn RenderDevLog(Tag:String, Message:String) {
37+
// The `dev_log!` macro expands to a conditional on `IsEnabled(Tag)`
38+
// - when the tag is off, the entire call is a no-op besides the
39+
// string allocation on the caller side. `$Tag:expr` in the macro
40+
// accepts `&str` / `&String` / `String` interchangeably.
41+
let TagRef:&str = &Tag;
42+
dev_log!(TagRef, "[RenderDevLog] {}", Message);
43+
}

Source/Binary/IPC/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ pub mod CacheStatsCommand;
5252
pub mod ProcessCommand;
5353
pub mod HealthCommand;
5454
pub mod WorkspaceFolderCommand;
55+
pub mod RenderDevLogCommand;

Source/Binary/Main/Entry.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ pub fn Fn() {
553553
crate::Binary::IPC::HealthCommand::cocoon_search_service_health,
554554
crate::Binary::IPC::HealthCommand::cocoon_debug_service_health,
555555
crate::Binary::IPC::HealthCommand::shared_process_service_health,
556+
crate::Binary::IPC::RenderDevLogCommand::RenderDevLog,
556557
])
557558
.build(tauri::generate_context!())
558559
.expect("FATAL: Error while building Mountain Tauri application")

Source/IPC/DevLog.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,21 @@
7373
//! | `cocoon` | Cocoon sidecar: spawn, health, handshake |
7474
//! | `bootstrap` | Effect-TS bootstrap stages |
7575
//! | `preload` | Preload: globals, polyfills, ipcRenderer |
76+
//!
77+
//! ### Batch 1 diagnostic tags (Row 1-3 fix surfaces)
78+
//!
79+
//! Narrow tags added to isolate the architectural gaps surfaced by the
80+
//! analysis table. Enable selectively with e.g.
81+
//! `LAND_DEV_LOG=notif-drop,git,tree-view` to filter to just the
82+
//! subsystem under investigation.
83+
//!
84+
//! | Tag | Scope |
85+
//! |---------------------|-----------------------------------------------------------------------|
86+
//! | `notif-drop` | Notifications that hit the `_ => {}` default arm (dropped silently) |
87+
//! | `provider-register` | Accepted `register_*_provider` notifications + handle + extension id |
88+
//! | `channel-stub` | Wind/Output `TauriMainProcessService.call` stub-hit vs route vs miss |
89+
//! | `git` | `localGit` channel, `GitExec` RPC, SCM provider group updates |
90+
//! | `tree-view` | `tree.register`, `GetTreeChildren`, `sky://tree-view/create` emit |
7691
7792
use std::{
7893
fs::{File, OpenOptions, create_dir_all},

Source/RPC/CocoonService/SCM.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ pub async fn UpdateScmGroup(Service:&CocoonServiceImpl, req:UpdateScmGroupReques
8282

8383
pub async fn GitExec(Service:&CocoonServiceImpl, req:GitExecRequest) -> Result<Response<GitExecResponse>, Status> {
8484
dev_log!("cocoon", "[CocoonService] git_exec: {}", req.args.join(" "));
85+
dev_log!(
86+
"git",
87+
"[Git] exec-begin cwd={} args=[{}]",
88+
if req.repository_path.is_empty() {
89+
"<cwd>".to_string()
90+
} else {
91+
req.repository_path.clone()
92+
},
93+
req.args.join(" ")
94+
);
8595

8696
let WorkingDir = if req.repository_path.is_empty() {
8797
std::env::current_dir().unwrap_or_default()
@@ -96,6 +106,13 @@ pub async fn GitExec(Service:&CocoonServiceImpl, req:GitExecRequest) -> Result<R
96106
.await
97107
.map_err(|Error| {
98108
dev_log!("cocoon", "error: [CocoonService] git_exec failed to spawn: {}", Error);
109+
dev_log!(
110+
"git",
111+
"[Git] exec-spawn-fail cwd={:?} args=[{}] error={}",
112+
WorkingDir,
113+
req.args.join(" "),
114+
Error
115+
);
99116
Status::internal(format!("git_exec: failed to spawn git: {}", Error))
100117
})?;
101118

@@ -107,6 +124,14 @@ pub async fn GitExec(Service:&CocoonServiceImpl, req:GitExecRequest) -> Result<R
107124
Output.stdout.len(),
108125
Output.stderr.len()
109126
);
127+
dev_log!(
128+
"git",
129+
"[Git] exec-done args=[{}] exit={} stdout={} stderr={}",
130+
req.args.join(" "),
131+
ExitCode,
132+
Output.stdout.len(),
133+
Output.stderr.len()
134+
);
110135

111136
// Combine stdout lines into repeated string output; prepend stderr lines
112137
// with "stderr: " prefix so extension can differentiate them.

Source/RPC/CocoonService/TreeView.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ pub async fn GetTreeChildren(
5959
req:GetTreeChildrenRequest,
6060
) -> Result<Response<GetTreeChildrenResponse>, Status> {
6161
dev_log!("cocoon", "[CocoonService] get_tree_children: view={}", req.view_id);
62+
dev_log!(
63+
"tree-view",
64+
"[TreeView] get-children view={} parent_handle={} - STUB returns empty (Mountain→Cocoon round-trip not wired)",
65+
req.view_id,
66+
req.tree_item_handle
67+
);
6268

6369
// Tree children are fetched by forwarding to Cocoon via the generic RPC path.
6470
// The extension registers a TreeDataProvider; when Sky needs children,

Source/Track/Effect/CreateEffectForRequest/TreeView.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ pub fn CreateEffect<R:Runtime>(
6464
DispatchAt.elapsed().as_millis(),
6565
RegisteredNs
6666
);
67+
dev_log!(
68+
"tree-view",
69+
"[TreeView] register view={} result={} elapsed={}ms",
70+
ViewIdForLog,
71+
if Result.is_ok() { "ok" } else { "err" },
72+
DispatchAt.elapsed().as_millis()
73+
);
6774

6875
// Notify Wind/Sky that a data provider now exists for this
6976
// view, so the renderer can set `treeView.dataProvider` on
@@ -87,6 +94,20 @@ pub fn CreateEffect<R:Runtime>(
8794
ViewIdForLog,
8895
Error
8996
);
97+
dev_log!(
98+
"tree-view",
99+
"[TreeView] emit-fail channel={} view={} error={}",
100+
SkyEvent::TreeViewCreate.AsStr(),
101+
ViewIdForLog,
102+
Error
103+
);
104+
} else {
105+
dev_log!(
106+
"tree-view",
107+
"[TreeView] emit-ok channel={} view={}",
108+
SkyEvent::TreeViewCreate.AsStr(),
109+
ViewIdForLog
110+
);
90111
}
91112
}
92113

Source/Vine/Server/MountainVinegRPCService.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,15 @@ impl MountainService for MountainVinegRPCService {
838838
Handle,
839839
Selector
840840
);
841+
dev_log!(
842+
"provider-register",
843+
"[ProviderRegister] accepted method={} type={} handle={} lang={} ext={}",
844+
MethodName,
845+
ProviderTypeName,
846+
Handle,
847+
Selector,
848+
ExtId
849+
);
841850
// Provider registration happens in CocoonService.RegisterProvider via the typed
842851
// RPC path. This notification path is a fallback for providers registered
843852
// via the vscode API shim.
@@ -872,6 +881,22 @@ impl MountainService for MountainVinegRPCService {
872881
},
873882
_ => {
874883
dev_log!("grpc", "[MountainVinegRPCService] Cocoon notification: {}", MethodName);
884+
// No typed match arm exists for this notification - it hits
885+
// the default path and becomes a `cocoon:<method>` Tauri
886+
// event that Wind may or may not listen for. The
887+
// `notif-drop` tag surfaces every fall-through so we can
888+
// tell at a glance which notifications Cocoon emits that
889+
// Mountain has no first-class handler for (register_*
890+
// provider variants beyond the seven handled above,
891+
// register_debug_adapter, register_task_provider,
892+
// register_uri_handler, register_file_system_provider, …).
893+
dev_log!(
894+
"notif-drop",
895+
"[NotifDrop] method={} payload_bytes={} (falls through to cocoon:{} event)",
896+
MethodName,
897+
NotificationData.parameter.len(),
898+
MethodName
899+
);
875900
// Forward all unknown notifications as Tauri events so Wind
876901
// can subscribe to any Cocoon-originated event.
877902
let EventName = format!("cocoon:{}", MethodName);

0 commit comments

Comments
 (0)