diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-23 00:48:22 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-23 00:48:22 +0300 |
| commit | 40750418049c5125724b004c8f55ae66ca77edcf (patch) | |
| tree | d72ecadb0506c3643ffaa5fe7cf40f22c90d967a /src/app | |
| parent | 3d6f3e78624f1308a360cbf02eeca3fec2434436 (diff) | |
feat(logging): add robust rotating support logs
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/actions.rs | 27 | ||||
| -rw-r--r-- | src/app/api.rs | 82 | ||||
| -rw-r--r-- | src/app/config_io.rs | 2 | ||||
| -rw-r--r-- | src/app/creation.rs | 9 | ||||
| -rw-r--r-- | src/app/input/modal.rs | 22 | ||||
| -rw-r--r-- | src/app/mod.rs | 4 |
6 files changed, 104 insertions, 42 deletions
diff --git a/src/app/actions.rs b/src/app/actions.rs index 33952b9f..b1bdfc63 100644 --- a/src/app/actions.rs +++ b/src/app/actions.rs @@ -105,6 +105,8 @@ impl AppState { if idx < self.workspaces.len() { self.active = Some(idx); self.selected = idx; + let workspace_id = self.workspaces[idx].id.clone(); + crate::logging::workspace_focused(&workspace_id); self.mark_session_dirty(); if matches!( self.agent_panel_scope, @@ -114,7 +116,10 @@ impl AppState { } self.ensure_workspace_visible(idx); if let Some(ws) = self.workspaces.get_mut(idx) { - ws.switch_tab(ws.active_tab); + let active_tab = ws.active_tab; + ws.switch_tab(active_tab); + let tab_id = format!("{}:{}", workspace_id, active_tab + 1); + crate::logging::tab_focused(&workspace_id, &tab_id); } self.tab_scroll_follow_active = true; self.refresh_tab_bar_view(); @@ -152,8 +157,14 @@ impl AppState { } pub fn switch_tab(&mut self, idx: usize) { - if let Some(ws) = self.active.and_then(|i| self.workspaces.get_mut(i)) { + if let Some(ws_idx) = self.active { + let Some(ws) = self.workspaces.get_mut(ws_idx) else { + return; + }; ws.switch_tab(idx); + let workspace_id = ws.id.clone(); + let tab_id = format!("{}:{}", workspace_id, idx + 1); + crate::logging::tab_focused(&workspace_id, &tab_id); self.mark_session_dirty(); self.tab_scroll_follow_active = true; self.refresh_tab_bar_view(); @@ -258,8 +269,8 @@ impl AppState { return; } self.mark_session_dirty(); - let name = self.workspaces[self.selected].display_name(); - info!(workspace = %name, "workspace closed"); + let workspace_id = self.workspaces[self.selected].id.clone(); + crate::logging::workspace_closed(&workspace_id); self.workspaces.remove(self.selected); if self.workspaces.is_empty() { self.active = None; @@ -394,8 +405,14 @@ impl AppState { self.close_selected_workspace(); return; } - if let Some(ws) = self.active.and_then(|i| self.workspaces.get_mut(i)) { + if let Some(ws_idx) = self.active { + let Some(ws) = self.workspaces.get_mut(ws_idx) else { + return; + }; + let workspace_id = ws.id.clone(); + let closing_tab_id = format!("{}:{}", workspace_id, ws.active_tab + 1); ws.close_active_tab(); + crate::logging::tab_closed(&workspace_id, &closing_tab_id); self.tab_scroll_follow_active = true; self.refresh_tab_bar_view(); } diff --git a/src/app/api.rs b/src/app/api.rs index b07c1267..364097dc 100644 --- a/src/app/api.rs +++ b/src/app/api.rs @@ -333,6 +333,7 @@ impl App { if let Some(label) = params.label { if let Some(workspace) = self.state.workspaces.get_mut(index) { workspace.set_custom_name(label); + crate::logging::workspace_renamed(&workspace.id); } } let workspace = self.workspace_info(index); @@ -428,6 +429,7 @@ impl App { .unwrap(); }; ws.set_custom_name(params.label.clone()); + crate::logging::workspace_renamed(&ws.id); self.schedule_session_save(); self.emit_event(crate::api::schema::EventEnvelope { event: crate::api::schema::EventKind::WorkspaceRenamed, @@ -604,6 +606,10 @@ impl App { match result { Ok(tab_idx) => { if let Some(label) = label { + let workspace_id = self.state.workspaces[ws_idx].id.clone(); + let tab_id = self + .public_tab_id(ws_idx, tab_idx) + .unwrap_or_else(|| format!("{}:{}", workspace_id, tab_idx + 1)); if let Some(tab) = self .state .workspaces @@ -611,6 +617,7 @@ impl App { .and_then(|ws| ws.tabs.get_mut(tab_idx)) { tab.set_custom_name(label); + crate::logging::tab_renamed(&workspace_id, &tab_id); } } if focus { @@ -682,6 +689,10 @@ impl App { }) .unwrap(); }; + let workspace_id = self.state.workspaces[ws_idx].id.clone(); + let tab_id = self + .public_tab_id(ws_idx, tab_idx) + .unwrap_or_else(|| format!("{}:{}", workspace_id, tab_idx + 1)); let Some(tab) = self .state .workspaces @@ -698,6 +709,7 @@ impl App { .unwrap(); }; tab.set_custom_name(params.label.clone()); + crate::logging::tab_renamed(&workspace_id, &tab_id); self.schedule_session_save(); self.emit_event(crate::api::schema::EventEnvelope { event: crate::api::schema::EventKind::TabRenamed, @@ -1237,6 +1249,7 @@ impl App { }); match path { Ok(path) => { + crate::logging::integration_action("install", "pi", "ok"); vec![format!("installed pi integration to {}", path.display())] } Err(response) => return response, @@ -1254,16 +1267,19 @@ impl App { .unwrap() }); match installed { - Ok(installed) => vec![ - format!( - "installed claude integration hook to {}", - installed.hook_path.display() - ), - format!( - "ensured claude settings at {}", - installed.settings_path.display() - ), - ], + Ok(installed) => { + crate::logging::integration_action("install", "claude", "ok"); + vec![ + format!( + "installed claude integration hook to {}", + installed.hook_path.display() + ), + format!( + "ensured claude settings at {}", + installed.settings_path.display() + ), + ] + } Err(response) => return response, } } @@ -1279,20 +1295,23 @@ impl App { .unwrap() }); match installed { - Ok(installed) => vec![ - format!( - "installed codex integration hook to {}", - installed.hook_path.display() - ), - format!( - "ensured codex hooks at {}", - installed.hooks_path.display() - ), - format!( - "ensured codex config at {}", - installed.config_path.display() - ), - ], + Ok(installed) => { + crate::logging::integration_action("install", "codex", "ok"); + vec![ + format!( + "installed codex integration hook to {}", + installed.hook_path.display() + ), + format!( + "ensured codex hooks at {}", + installed.hooks_path.display() + ), + format!( + "ensured codex config at {}", + installed.config_path.display() + ), + ] + } Err(response) => return response, } } @@ -1308,10 +1327,13 @@ impl App { .unwrap() }); match installed { - Ok(installed) => vec![format!( - "installed opencode integration plugin to {}", - installed.plugin_path.display() - )], + Ok(installed) => { + crate::logging::integration_action("install", "opencode", "ok"); + vec![format!( + "installed opencode integration plugin to {}", + installed.plugin_path.display() + )] + } Err(response) => return response, } } @@ -1341,6 +1363,7 @@ impl App { }); match result { Ok(result) => { + crate::logging::integration_action("uninstall", "pi", "ok"); if result.removed_extension { vec![format!( "removed pi integration extension at {}", @@ -1369,6 +1392,7 @@ impl App { }); match result { Ok(result) => { + crate::logging::integration_action("uninstall", "claude", "ok"); let mut messages = Vec::new(); if result.removed_hook_file { messages.push(format!( @@ -1410,6 +1434,7 @@ impl App { }); match result { Ok(result) => { + crate::logging::integration_action("uninstall", "codex", "ok"); let mut messages = Vec::new(); if result.removed_hook_file { messages.push(format!( @@ -1455,6 +1480,7 @@ impl App { }); match result { Ok(result) => { + crate::logging::integration_action("uninstall", "opencode", "ok"); if result.removed_plugin { vec![format!( "removed opencode integration plugin at {}", diff --git a/src/app/config_io.rs b/src/app/config_io.rs index 5d4b2b13..6770d61e 100644 --- a/src/app/config_io.rs +++ b/src/app/config_io.rs @@ -8,6 +8,7 @@ impl App { let path = crate::config::config_path(); if let Some(parent) = path.parent() { if let Err(err) = std::fs::create_dir_all(parent) { + crate::logging::config_write_failed(&path, error_context, &err.to_string()); self.state.config_diagnostic = Some(format!("failed to save {error_context}: {err}")); self.config_diagnostic_deadline = @@ -19,6 +20,7 @@ impl App { let content = std::fs::read_to_string(&path).unwrap_or_default(); let new_content = update(&content); if let Err(err) = std::fs::write(&path, new_content) { + crate::logging::config_write_failed(&path, error_context, &err.to_string()); self.state.config_diagnostic = Some(format!("failed to save {error_context}: {err}")); self.config_diagnostic_deadline = Some(std::time::Instant::now() + std::time::Duration::from_secs(5)); diff --git a/src/app/creation.rs b/src/app/creation.rs index dd2833e0..508bf023 100644 --- a/src/app/creation.rs +++ b/src/app/creation.rs @@ -89,6 +89,12 @@ impl App { ws.switch_tab(idx); self.state.mode = Mode::Terminal; } + let workspace_id = self.state.workspaces[ws_idx].id.clone(); + let tab_id = self + .public_tab_id(ws_idx, idx) + .unwrap_or_else(|| format!("{}:{}", workspace_id, idx + 1)); + let root_pane = self.state.workspaces[ws_idx].tabs[idx].root_pane.raw(); + crate::logging::tab_created(&workspace_id, &tab_id, root_pane); self.schedule_session_save(); Ok(idx) } @@ -112,6 +118,9 @@ impl App { ws.refresh_git_ahead_behind(); self.state.workspaces.push(ws); let idx = self.state.workspaces.len() - 1; + let workspace_id = self.state.workspaces[idx].id.clone(); + let root_pane = self.state.workspaces[idx].tabs[0].root_pane.raw(); + crate::logging::workspace_created(&workspace_id, root_pane); if focus || self.state.active.is_none() { self.state.switch_workspace(idx); self.state.mode = Mode::Terminal; diff --git a/src/app/input/modal.rs b/src/app/input/modal.rs index 5c3108f2..aa25ea1e 100644 --- a/src/app/input/modal.rs +++ b/src/app/input/modal.rs @@ -263,7 +263,9 @@ pub(super) fn apply_rename_action(state: &mut AppState, action: ModalAction) { match state.mode { Mode::RenameWorkspace if !state.workspaces.is_empty() => { if !new_name.is_empty() { + let workspace_id = state.workspaces[state.selected].id.clone(); state.workspaces[state.selected].set_custom_name(new_name); + crate::logging::workspace_renamed(&workspace_id); state.mark_session_dirty(); } } @@ -278,13 +280,19 @@ pub(super) fn apply_rename_action(state: &mut AppState, action: ModalAction) { }; } Mode::RenameTab => { - if let Some(ws) = state.active.and_then(|i| state.workspaces.get_mut(i)) { - if let Some(tab) = ws.active_tab_mut() { - let keep_auto_name = - tab.is_auto_named() && new_name == tab.number.to_string(); - if !new_name.is_empty() && !keep_auto_name { - tab.set_custom_name(new_name); - state.mark_session_dirty(); + if let Some(ws_idx) = state.active { + if let Some(ws) = state.workspaces.get_mut(ws_idx) { + let workspace_id = ws.id.clone(); + let active_tab = ws.active_tab; + if let Some(tab) = ws.active_tab_mut() { + let keep_auto_name = + tab.is_auto_named() && new_name == tab.number.to_string(); + if !new_name.is_empty() && !keep_auto_name { + tab.set_custom_name(new_name); + let tab_id = format!("{}:{}", workspace_id, active_tab + 1); + crate::logging::tab_renamed(&workspace_id, &tab_id); + state.mark_session_dirty(); + } } } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 78681e06..14c50f7f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -182,7 +182,7 @@ impl App { render_dirty.clone(), ); if ws.is_empty() { - info!("session file found but no workspaces restored"); + crate::logging::session_restored(0, "empty"); ( Vec::new(), None, @@ -192,7 +192,7 @@ impl App { snap.sidebar_section_split.unwrap_or(0.5), ) } else { - info!(count = ws.len(), "session restored"); + crate::logging::session_restored(ws.len(), "ok"); let active = snap.active.filter(|&i| i < ws.len()); let selected = snap.selected.min(ws.len().saturating_sub(1)); ( |
