Reduce session logging and background churn

This commit is contained in:
Ryan Ward
2026-09-02 15:13:24 -05:00
parent 13cbb232ee
commit b115946534
29 changed files with 268 additions and 127 deletions
Generated
+1
View File
@@ -229,6 +229,7 @@ dependencies = [
"dirs 6.0.0",
"dunce",
"filetime",
"fs4",
"futures",
"galaxy_core",
"galaxy_graphql",
+1
View File
@@ -178,6 +178,7 @@ font-kit = { git = "https://github.com/warpdotdev/font-kit.git", rev = "a04b225e
futures = { version = "0.3", features = ["executor", "thread-pool"] }
futures-lite = "1.13.0"
futures-util = { version = "0.3", default-features = false }
fs4 = "0.13.1"
get-size = { version = "0.1.4", features = ["derive"] }
globset = "0.4.18"
gloo = { version = "0.11.0", default-features = false, features = [
-7
View File
@@ -216,13 +216,6 @@ impl BedrockClient {
tools.len()
);
log::info!(
"[bedrock] Sending request payload to Bedrock:\nSystem Prompt: {:?}\nMessages: {:#?}\nTools: {:#?}",
system_prompt,
messages,
tools
);
let converted = build_converse_request(
messages.clone(),
system_prompt.clone(),
+18 -4
View File
@@ -269,14 +269,20 @@ impl CurrentPrompt {
if let Some(session) = session {
let buffer_text = editor.as_ref(ctx).buffer_text(ctx);
let mut should_notify = false;
for (kind, state) in me.states.iter_mut() {
state.should_render =
kind.should_render(&buffer_text, session.aliases());
let should_render = kind.should_render(&buffer_text, session.aliases());
if state.should_render != should_render {
state.should_render = should_render;
should_notify = true;
}
}
if should_notify {
ctx.notify();
}
}
}
}
});
}
@@ -321,7 +327,10 @@ impl CurrentPrompt {
}
fn update_chip_value(&mut self, chip_kind: &ContextChipKind, value: Option<ChipValue>) {
log::debug!("Updating prompt value of {chip_kind:?} to {value:?}");
log::trace!(
"Updating prompt value of {chip_kind:?}; has_value={}",
value.is_some()
);
if let Some(state) = self.states.get_mut(chip_kind) {
if state.last_computed_value != value {
state.last_computed_value = value;
@@ -332,16 +341,21 @@ impl CurrentPrompt {
}
fn update_on_click_value(&mut self, chip_kind: &ContextChipKind, value: Option<Vec<String>>) {
log::debug!("Updating prompt on_click value of {chip_kind:?} to {value:?}");
log::trace!(
"Updating prompt on_click value of {chip_kind:?}; item_count={}",
value.as_ref().map_or(0, Vec::len)
);
let filter_values = match chip_kind {
ContextChipKind::ShellGitBranch => self.filter_git_branch_on_click_values(value),
_ => value,
};
if let Some(state) = self.states.get_mut(chip_kind) {
if state.last_on_click_values != filter_values {
state.last_on_click_values = filter_values;
let _ = self.update_tx.try_send(());
}
}
}
fn set_chip_availability(
&mut self,
-1
View File
@@ -47,7 +47,6 @@ impl PromptSnapshot {
})
.collect_vec();
log::debug!("Current prompt snapshot: {chips:?}");
Self {
chips,
same_line_prompt_enabled: current_prompt.same_line_prompt_enabled(),
+4 -1
View File
@@ -492,7 +492,10 @@ impl EditorView {
self.stop_transcribing_voice_input(ctx);
match result {
Ok(transcribe_response) => {
log::debug!("Transcribed voice input: {transcribe_response:?}");
log::debug!(
"Transcribed voice input; characters={}",
transcribe_response.chars().count()
);
self.user_insert(&transcribe_response, ctx);
}
Err(e) => match e {
+2 -2
View File
@@ -2396,7 +2396,7 @@ pub(crate) fn app_callbacks(
// Persist the final app state before tearing down the writer.
// This ensures the latest session (tabs, CWD, conversations) is saved
// even if the termination bypassed individual window-close events.
ctx.dispatch_global_action("workspace:save_app", &());
workspace::save_app_urgently(ctx);
NotebookManager::handle(ctx).update(ctx, |manager, ctx| {
// Notebooks are only saved periodically, so ensure that any pending changes have
@@ -2634,7 +2634,7 @@ pub(crate) fn app_callbacks(
stack.handle_window_closed(window_data, ctx);
});
}
ctx.dispatch_global_action("workspace:save_app", &());
workspace::save_app_urgently(ctx);
})),
on_window_moved: Some(Box::new(move |ctx| {
ctx.dispatch_global_action("workspace:save_app", &());
+6 -6
View File
@@ -499,7 +499,7 @@ impl PaneContent for TerminalPane {
let ambient_model = ambient_model.as_ref(app);
let task_id = ambient_model.task_id();
log::info!("[session-save] pane=viewer/ambient task_id={task_id:?}");
log::trace!("[session-snapshot] pane=viewer/ambient task_id={task_id:?}");
return LeafContents::AmbientAgent(AmbientAgentPaneSnapshot {
uuid: self.uuid.clone(),
task_id,
@@ -507,7 +507,7 @@ impl PaneContent for TerminalPane {
}
let cwd = view.pwd_if_local(app);
log::info!("[session-save] pane=viewer cwd={cwd:?} is_active={is_active}");
log::trace!("[session-snapshot] pane=viewer cwd={cwd:?} is_active={is_active}");
LeafContents::Terminal(TerminalPaneSnapshot {
uuid: self.uuid.clone(),
cwd,
@@ -533,14 +533,14 @@ impl PaneContent for TerminalPane {
// can be restored via the ambient agent task if one exists.
let task_id = view.model.lock().ambient_agent_task_id();
if task_id.is_some() {
log::info!("[session-save] pane=transcript/ambient task_id={task_id:?}");
log::trace!("[session-snapshot] pane=transcript/ambient task_id={task_id:?}");
LeafContents::AmbientAgent(AmbientAgentPaneSnapshot {
uuid: self.uuid.clone(),
task_id,
})
} else {
let cwd = view.pwd_if_local(app);
log::info!("[session-save] pane=transcript cwd={cwd:?} is_active={is_active}");
log::trace!("[session-snapshot] pane=transcript cwd={cwd:?} is_active={is_active}");
LeafContents::Terminal(TerminalPaneSnapshot {
uuid: self.uuid.clone(),
cwd,
@@ -584,8 +584,8 @@ impl PaneContent for TerminalPane {
});
let cwd = view.pwd_if_local(app);
log::info!(
"[session-save] pane=terminal cwd={cwd:?} is_active={is_active} \
log::trace!(
"[session-snapshot] pane=terminal cwd={cwd:?} is_active={is_active} \
conversations={} active_conversation={active_conversation_id:?} \
has_shell_launch_data={} has_input_config=true",
conversation_ids_to_restore.len(),
+17 -1
View File
@@ -1000,7 +1000,7 @@ pub enum OpenAIProviderKind {
///
/// Multiple providers can be configured simultaneously. Each provider has its own endpoint,
/// credentials, and model list.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, schemars::JsonSchema)]
#[derive(Clone, Serialize, Deserialize, PartialEq, schemars::JsonSchema)]
#[schemars(description = "Configuration for a direct model provider endpoint.")]
pub struct OpenAIProviderConfig {
#[serde(default)]
@@ -1027,6 +1027,22 @@ pub struct OpenAIProviderConfig {
pub models: Vec<OpenAIModelConfig>,
}
impl std::fmt::Debug for OpenAIProviderConfig {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("OpenAIProviderConfig")
.field("kind", &self.kind)
.field("enabled", &self.enabled)
.field("name", &self.name)
.field("base_url", &self.base_url)
.field("api_key_configured", &self.api_key.is_some())
.field("project_id", &self.project_id)
.field("location", &self.location)
.field("models", &self.models)
.finish()
}
}
impl settings_value::SettingsValue for OpenAIProviderConfig {}
fn default_acp_agent_id() -> String {
+3
View File
@@ -391,6 +391,9 @@ fn native_provider_settings_roundtrip_with_vertex_configuration() {
}))
.expect("Native OpenAI provider settings should deserialize");
assert_eq!(native_openai.kind, OpenAIProviderKind::OpenAI);
let debug_output = format!("{native_openai:?}");
assert!(!debug_output.contains("sk-test"));
assert!(debug_output.contains("api_key_configured: true"));
}
#[test]
@@ -260,10 +260,12 @@ fn wire_up_terminal_view_session_sharing(
if *SessionSettings::as_ref(ctx).honor_ps1 {
return
}
let Some(network) = session_sharer_clone.borrow().clone() else {
return;
};
let prompt_snapshot = current_prompt.read(ctx, |current_prompt, ctx| {
PromptSnapshot::from_current_prompt(current_prompt, ctx)
});
if let Some(network) = session_sharer_clone.borrow().as_ref() {
let Ok(serialized_prompt) = serde_json::to_string(&prompt_snapshot) else {
log::error!("Failed to serialize prompt snapshot to send active prompt update to shared session server");
return
@@ -271,7 +273,6 @@ fn wire_up_terminal_view_session_sharing(
network.update(ctx, |network, _| {
network.send_active_prompt_update_if_changed(session_sharing_protocol::common::ActivePrompt::WarpPrompt(serialized_prompt))
});
}
});
let session_sharer_clone = session_sharer.clone();
@@ -264,11 +264,11 @@ fn add_local_machine_env(env: &mut BTreeMap<OsString, EnvEntry>) {
let Ok(value) = reg_value_to_string(&value, &name) else {
safe_info!(
safe: ("Unable to convert value for key {name:?}"),
full: ("Unable to convert value for key {name:?}: {:?}", value.bytes)
full: ("Unable to convert value for key {name:?}")
);
continue;
};
log::trace!("adding SYS env: {name:?} = {value:?}");
log::trace!("adding SYS env: {name:?}");
env.insert(
map_key(name.clone().into()),
EnvEntry {
@@ -289,7 +289,7 @@ fn add_user_env(env: &mut BTreeMap<OsString, EnvEntry>) {
let Ok(value) = reg_value_to_string(&value, &name) else {
safe_info!(
safe: ("Unable to convert value for key {name:?}"),
full: ("Unable to convert value for key {name:?}: {:?}", value.bytes)
full: ("Unable to convert value for key {name:?}")
);
continue;
};
@@ -309,7 +309,7 @@ fn add_user_env(env: &mut BTreeMap<OsString, EnvEntry>) {
value
};
log::trace!("adding USER env: {name:?} = {value:?}");
log::trace!("adding USER env: {name:?}");
env.insert(
map_key(name.clone().into()),
EnvEntry {
@@ -19,7 +19,10 @@ pub(super) fn parse_ansi_c_quoted_string(quoted_string: String) -> String {
if quoted_string.trim().is_empty() {
return quoted_string;
}
log::debug!("Attempting to parse the following ANSI C escaped shell output: {quoted_string}");
log::debug!(
"Attempting to parse ANSI-C escaped shell output; bytes={}",
quoted_string.len()
);
let Some(quoted_string_without_prefix) = quoted_string.strip_prefix("$\'") else {
log::warn!("Tried to parse ANSI-C quoted string but $\' prefix was not present");
+3 -9
View File
@@ -653,10 +653,7 @@ impl<'a, H: Handler + 'a, W: io::Write> Performer<'a, H, W> {
fn handle_decoded_data(&mut self, decoded_data: Result<Vec<u8>, hex::FromHexError>) {
match decoded_data {
Ok(decoded_data) => {
safe_debug!(
safe: ("Decoded payload"),
full: ("Decoded payload string: {:?}", std::str::from_utf8(&decoded_data))
);
log::debug!("Decoded shell hook payload; bytes={}", decoded_data.len());
let hook = serde_json::from_slice::<DProtoHook>(&decoded_data);
if let Ok(hook) = &hook {
@@ -691,10 +688,7 @@ impl<'a, H: Handler + 'a, W: io::Write> Performer<'a, H, W> {
return;
}
};
safe_debug!(
safe: ("Decoded payload"),
full: ("Decoded payload string: {:?}", serde_json::to_string(&hook))
);
log::debug!("Decoded key-value shell hook payload");
self.handle_decoded_hook(Ok(hook));
}
Some(&WARP_KV_ENTRY_BYTE) => {
@@ -888,7 +882,7 @@ where
.map(|parts| parts.join(";").trim().to_owned());
if let Ok(body) = body {
if !body.is_empty() {
log::info!("Received OSC 9 notification: {}", body);
log::info!("Received OSC 9 notification; bytes={}", body.len());
self.handler.pluggable_notification(None, body);
return;
}
-1
View File
@@ -3058,7 +3058,6 @@ impl BlockList {
if let Some(prompt_snapshot) = &block.prompt_snapshot {
if let Ok(prompt_snapshot) = serde_json::from_str(prompt_snapshot) {
log::debug!("Restored prompt: {prompt_snapshot:?}");
self.active_block_mut().set_prompt_snapshot(prompt_snapshot);
}
}
-1
View File
@@ -356,7 +356,6 @@ impl Sessions {
let session = Session::new(session_info.clone(), command_executor);
log::info!("Shell is bootstrapped with session_id {:?}", session.id());
log::debug!("Session details: {session:?}");
let session = Arc::new(session);
self.sessions.insert(session.id(), session.clone());
+107 -35
View File
@@ -1,14 +1,16 @@
use std::path::PathBuf;
use std::time::Duration;
use ::settings::ToggleableSetting;
use galaxy_core::execution_mode::AppExecutionMode;
use galaxy_graphql::mutations::create_anonymous_user::AnonymousUserType;
use galaxyui::r#async::{SpawnedFutureHandle, Timer};
use galaxyui::windowing::WindowManager;
use galaxyui::{AppContext, SingletonEntity, TypedActionView};
use galaxyui::{AppContext, Entity, ModelContext, SingletonEntity, TypedActionView};
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::AIAgentExchangeId;
use crate::app_state::get_app_state;
use crate::app_state::{get_app_state, AppState};
use crate::network::NetworkStatus;
use crate::persistence::ModelEvent;
use crate::root_view::OpenPath;
@@ -20,6 +22,102 @@ use crate::workspace::cross_window_tab_drag::CrossWindowTabDrag;
use crate::workspace::{Workspace, WorkspaceAction};
use crate::{auth, GlobalResourceHandlesProvider};
const SESSION_SAVE_DEBOUNCE: Duration = Duration::from_millis(250);
pub(crate) struct SessionSaveCoordinator {
last_enqueued_state: Option<AppState>,
pending_save: bool,
timer_generation: u64,
timer: Option<SpawnedFutureHandle>,
}
impl SessionSaveCoordinator {
pub(crate) fn new() -> Self {
Self {
last_enqueued_state: None,
pending_save: false,
timer_generation: 0,
timer: None,
}
}
fn request_save(&mut self, ctx: &mut ModelContext<Self>) {
if !session_save_is_enabled(ctx) {
return;
}
if self.timer.is_none() {
self.save_if_changed(ctx);
} else {
self.pending_save = true;
}
self.restart_timer(ctx);
}
fn save_urgently(&mut self, ctx: &mut ModelContext<Self>) {
self.timer_generation = self.timer_generation.wrapping_add(1);
if let Some(timer) = self.timer.take() {
timer.abort();
}
self.pending_save = false;
if session_save_is_enabled(ctx) {
self.save_if_changed(ctx);
}
}
fn restart_timer(&mut self, ctx: &mut ModelContext<Self>) {
if let Some(timer) = self.timer.take() {
timer.abort();
}
self.timer_generation = self.timer_generation.wrapping_add(1);
let generation = self.timer_generation;
self.timer = Some(ctx.spawn(
async move { Timer::after(SESSION_SAVE_DEBOUNCE).await },
move |coordinator, _, ctx| {
if coordinator.timer_generation != generation {
return;
}
coordinator.timer = None;
if std::mem::take(&mut coordinator.pending_save) {
coordinator.save_if_changed(ctx);
}
},
));
}
fn save_if_changed(&mut self, ctx: &mut ModelContext<Self>) {
let Some(model_event_sender) = GlobalResourceHandlesProvider::as_ref(ctx)
.get()
.model_event_sender
.clone()
else {
return;
};
let app_state = get_app_state(ctx);
if self.last_enqueued_state.as_ref() == Some(&app_state) {
return;
}
if let Err(err) = model_event_sender.send(ModelEvent::Snapshot(app_state.clone())) {
log::error!("Error trying to send model event {err:?}");
return;
}
self.last_enqueued_state = Some(app_state);
}
}
impl Entity for SessionSaveCoordinator {
type Event = ();
}
impl SingletonEntity for SessionSaveCoordinator {}
fn session_save_is_enabled(ctx: &AppContext) -> bool {
AppExecutionMode::as_ref(ctx).can_save_session()
&& *GeneralSettings::as_ref(ctx).restore_session
&& !CrossWindowTabDrag::as_ref(ctx).is_active()
}
/// Specifies where a forked conversation should be opened.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ForkedConversationDestination {
@@ -130,41 +228,15 @@ fn toggle_focus_reporting(_: &(), ctx: &mut AppContext) {
}
fn save_app(_: &(), ctx: &mut AppContext) {
if !AppExecutionMode::as_ref(ctx).can_save_session() {
return;
SessionSaveCoordinator::handle(ctx).update(ctx, |coordinator, ctx| {
coordinator.request_save(ctx);
});
}
if !*GeneralSettings::as_ref(ctx).restore_session {
return;
}
// While a cross-window tab drag is active, the dragged tab's pane group
// is in flight between source and preview windows and `get_app_state`
// would produce a snapshot with zero windows. Persisting that snapshot
// wipes the on-disk session via `save_app_state`'s delete-then-insert
// transaction. `save_app` fires from window move / focus / resize /
// close callbacks (see `app_callbacks` in `lib.rs`), all of which run
// during a drag, so we have to short-circuit at this boundary. The
// first save after the drag finalizes will rewrite the snapshot.
if CrossWindowTabDrag::as_ref(ctx).is_active() {
return;
}
let Some(model_event_sender) = GlobalResourceHandlesProvider::as_ref(ctx)
.get()
.model_event_sender
.clone()
else {
return;
};
// Only compute the app state if we're definitely going to use it.
let app_state = get_app_state(ctx);
let event = ModelEvent::Snapshot(app_state);
if let Err(err) = model_event_sender.send(event) {
log::error!("Error trying to send model event {err:?}");
}
pub(crate) fn save_app_urgently(ctx: &mut AppContext) {
SessionSaveCoordinator::handle(ctx).update(ctx, |coordinator, ctx| {
coordinator.save_urgently(ctx);
});
}
fn toggle_debug_network_status(_: &(), ctx: &mut AppContext) {
+2
View File
@@ -30,6 +30,7 @@ pub use action::{
};
pub use active_session::ActiveSession;
use galaxy_core::context_flag::ContextFlag;
pub(crate) use global_actions::save_app_urgently;
pub use global_actions::{
ForkAIConversationParams, ForkFromExchange, ForkedConversationDestination,
};
@@ -78,6 +79,7 @@ use crate::workspace::view::{
pub fn init(app: &mut AppContext) {
app.add_singleton_model(|_| WorkspaceRegistry::new());
app.add_singleton_model(|_| cross_window_tab_drag::CrossWindowTabDrag::new());
app.add_singleton_model(|_| global_actions::SessionSaveCoordinator::new());
use galaxyui::keymap::macros::*;
app.register_binding_validator::<Workspace>(is_binding_pty_compliant);
+1
View File
@@ -49,6 +49,7 @@ strsim.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = ["rt"] }
futures.workspace = true
fs4.workspace = true
generic-array = "0.14.7"
derivative.workspace = true
galaxy_core.workspace = true
+52 -10
View File
@@ -6,12 +6,14 @@
#![cfg(all(feature = "local_fs", not(target_family = "wasm")))]
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::{self, File, OpenOptions};
use std::path::{Path, PathBuf};
use std::time::Duration;
use anyhow::{Context, Result};
use galaxy_core::paths::state_dir;
use galaxy_util::standardized_path::StandardizedPath;
use galaxyui_core::r#async::Timer;
use galaxyui_core::{Entity, ModelContext, SingletonEntity};
use itertools::Itertools;
use repo_metadata::{RepoMetadataEvent, RepositoryIdentifier};
@@ -29,6 +31,7 @@ const MAX_INDEXED_BODY_BYTES: usize = 256_000;
const INDEX_DIRECTORY_NAME: &str = "local_project_indices";
const CURRENT_FILE_NAME: &str = "CURRENT";
const METADATA_FILE_NAME: &str = "metadata.json";
const INDEX_LOCK_RETRY_INTERVAL: Duration = Duration::from_millis(50);
// Field weights intentionally prioritize symbols and paths over implementation text.
define_search_schema!(
@@ -240,6 +243,7 @@ impl LocalProjectIndexManager {
});
let should_rebuild = manager.pending_rebuilds.remove(&root_path);
cleanup_old_generations(&manager.storage_root, &root_path);
drop(built_index.repository_lock);
if should_rebuild {
manager.start_rebuild(root_path, ctx);
}
@@ -286,7 +290,6 @@ impl LocalProjectIndexManager {
});
}
let should_rebuild = self.pending_rebuilds.remove(&root_path);
cleanup_old_generations(&self.storage_root, &root_path);
if should_rebuild {
self.start_rebuild(root_path, ctx);
}
@@ -350,7 +353,7 @@ impl LocalProjectIndexManager {
/// Removes a local project index and its persisted generations.
pub fn remove_index_for_path(&mut self, root_path: PathBuf, ctx: &mut ModelContext<Self>) {
let root_path = dunce::canonicalize(&root_path).unwrap_or(root_path);
self.remove_index(&root_path);
self.remove_index(&root_path, ctx);
ctx.emit(LocalProjectIndexEvent::IndexRemoved { root_path });
}
@@ -374,7 +377,7 @@ impl LocalProjectIndexManager {
let local_path = path.to_local_path_lossy();
let root_path = dunce::canonicalize(&local_path).unwrap_or(local_path);
if self.statuses.contains_key(&root_path) {
self.remove_index(&root_path);
self.remove_index(&root_path, ctx);
ctx.emit(LocalProjectIndexEvent::IndexRemoved { root_path });
}
return;
@@ -408,19 +411,30 @@ impl LocalProjectIndexManager {
}
}
fn remove_index(&mut self, root_path: &Path) {
fn remove_index(&mut self, root_path: &Path, ctx: &mut ModelContext<Self>) {
let root_path = dunce::canonicalize(root_path).unwrap_or_else(|_| root_path.to_path_buf());
self.indices.remove(&root_path);
self.statuses.remove(&root_path);
self.pending_rebuilds.remove(&root_path);
let epoch = self.rebuild_epochs.entry(root_path.clone()).or_default();
*epoch += 1;
let directory = repository_storage_directory(&self.storage_root, &root_path);
if let Err(error) = fs::remove_dir_all(directory) {
if error.kind() != std::io::ErrorKind::NotFound {
log::warn!("Failed to remove local project index: {error}");
let storage_root = self.storage_root.clone();
ctx.spawn(
async move {
let _repository_lock = acquire_repository_lock(&storage_root, &root_path).await?;
let directory = repository_storage_directory(&storage_root, &root_path);
match fs::remove_dir_all(directory) {
Ok(()) => Ok(()),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(error) => Err(anyhow::Error::new(error)),
}
},
|_, result, _| {
if let Err(error) = result {
log::warn!("Failed to remove local project index: {error:#}");
}
},
);
}
fn restore_persisted_indices(&mut self) {
@@ -503,6 +517,7 @@ struct BuiltLocalProjectIndex {
searcher: SimpleFullTextSearcher<LocalProjectIndexSchema>,
generation: String,
generation_directory: PathBuf,
repository_lock: File,
}
async fn build_persisted_index(
@@ -511,6 +526,10 @@ async fn build_persisted_index(
) -> std::result::Result<(PathBuf, BuiltLocalProjectIndex, usize), (PathBuf, anyhow::Error)> {
let error_root_path = root_path.clone();
let result = async {
// A desktop app and one or more CLI processes can share this storage root. Keep the
// repository snapshot, generation publication, and cleanup in one exclusive section so
// one process cannot delete another process's in-progress Tantivy generation.
let repository_lock = acquire_repository_lock(&storage_root, &root_path).await?;
let documents = build_documents(&root_path).await?;
let index_directory = repository_storage_directory(&storage_root, &root_path);
fs::create_dir_all(index_directory.join("generations"))?;
@@ -565,6 +584,7 @@ async fn build_persisted_index(
searcher,
generation,
generation_directory,
repository_lock,
},
documents.len(),
))
@@ -643,9 +663,31 @@ fn repository_storage_directory(storage_root: &Path, root_path: &Path) -> PathBu
storage_root.join(format_storage_directory_name(root_path))
}
fn repository_lock_path(storage_root: &Path, root_path: &Path) -> PathBuf {
storage_root.join(format!("{}.lock", format_storage_directory_name(root_path)))
}
async fn acquire_repository_lock(storage_root: &Path, root_path: &Path) -> Result<File> {
fs::create_dir_all(storage_root)?;
let lock_path = repository_lock_path(storage_root, root_path);
let lock_file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&lock_path)
.with_context(|| format!("Failed to open local index lock {}", lock_path.display()))?;
loop {
if fs4::fs_std::FileExt::try_lock_exclusive(&lock_file)? {
return Ok(lock_file);
}
Timer::after(INDEX_LOCK_RETRY_INTERVAL).await;
}
}
fn publish_generation(storage_root: &Path, root_path: &Path, generation: &str) -> Result<()> {
let index_directory = repository_storage_directory(storage_root, root_path);
let temporary_current = index_directory.join(format!(".{CURRENT_FILE_NAME}.tmp"));
let temporary_current =
index_directory.join(format!(".{CURRENT_FILE_NAME}.{}.tmp", uuid::Uuid::new_v4()));
fs::write(&temporary_current, generation.as_bytes())?;
fs::rename(&temporary_current, index_directory.join(CURRENT_FILE_NAME))?;
Ok(())
+15
View File
@@ -22,6 +22,10 @@ const CLI_LOG_SUBDIRECTORY: &str = "oz";
const SESSION_LOG_SUBDIRECTORY: &str = "session-logs";
const TEMP_LOG_FILE_SUFFIX: &str = "old.temp";
const INPUT_CLASSIFIER_LOG_TARGET: &str = "input_classifier";
const FILE_WATCHER_LOG_TARGET: &str = "notify";
const FILE_WATCHER_DEBOUNCER_LOG_TARGET: &str = "notify_debouncer_full";
const GLOBSET_LOG_TARGET: &str = "globset";
const IGNORE_WALKER_LOG_TARGET: &str = "ignore";
const TERMINAL_ANSI_HANDLER_LOG_TARGET: &str =
"galaxy::terminal::model::grid::grid_handler::ansi_handler";
@@ -593,6 +597,17 @@ fn init_internal(
// info/debug records. Keep initialization failures and classification errors, but omit the
// noisy pre-submission decision trail from full-session logs.
.filter(Some(INPUT_CLASSIFIER_LOG_TARGET), LevelFilter::Warn)
// notify logs every platform event and the debouncer logs every raw event at TRACE. A
// repository index can generate hundreds of thousands of these records, multiplying the
// underlying filesystem work with synchronous formatting and log-file writes. Keep
// watcher lifecycle information and all warnings while suppressing per-event payloads.
.filter(Some(FILE_WATCHER_LOG_TARGET), LevelFilter::Info)
.filter(Some(FILE_WATCHER_DEBOUNCER_LOG_TARGET), LevelFilter::Info)
// globset and ignore describe every compiled glob and opened ignore file at DEBUG. Those
// records are useful to their crate maintainers but scale with repository traversal and do
// not help diagnose Galaxy sessions. Preserve informational failures and summaries.
.filter(Some(GLOBSET_LOG_TARGET), LevelFilter::Info)
.filter(Some(IGNORE_WALKER_LOG_TARGET), LevelFilter::Info)
// Since we always pair an insertion with a deletion to avoid duplicate,
// tantivy will log a lot of warnings for deleting a non-existing doc.
.filter(Some("tantivy"), LevelFilter::Error)
@@ -1866,7 +1866,7 @@ impl EventLoop {
// will be dispatched to the active window as TypedCharacters/IME events.
let proxy = self.proxy.clone();
let on_input = Box::new(move |input: SoftKeyboardInput| {
log::debug!("Soft keyboard callback received input: {:?}", input);
log::debug!("Soft keyboard callback received input");
if let Err(e) = proxy.send_event(CustomEvent::SoftKeyboardInput(input)) {
log::error!("Failed to send SoftKeyboardInput event: {:?}", e);
}
@@ -1471,7 +1471,6 @@ impl Element for NewScrollable {
app: &AppContext,
) -> bool {
let Some(z_index) = self.child_max_z_index else {
log::warn!("Tried to handle event in scrollable before the element is painted");
return false;
};
@@ -458,9 +458,8 @@ impl Element for Resizable {
}
crate::Event::MouseMoved { position, .. } => {
// A mouse event over the dragbar should set the cursor
let Some(z_index) = self.z_index() else {
log::warn!("self.z_index() was None in `Resizable`");
return false;
let Some(z_index) = self.dragbar.z_index else {
return child_handled;
};
let hovering_dragbar = self.is_mouse_hovering_dragbar(ctx, *position);
let was_already_hovering =
@@ -1471,7 +1471,6 @@ impl Element for NewScrollable {
app: &AppContext,
) -> bool {
let Some(z_index) = self.child_max_z_index else {
log::warn!("Tried to handle event in scrollable before the element is painted");
return false;
};
@@ -458,9 +458,8 @@ impl Element for Resizable {
}
crate::Event::MouseMoved { position, .. } => {
// A mouse event over the dragbar should set the cursor
let Some(z_index) = self.z_index() else {
log::warn!("self.z_index() was None in `Resizable`");
return false;
let Some(z_index) = self.dragbar.z_index else {
return child_handled;
};
let hovering_dragbar = self.is_mouse_hovering_dragbar(ctx, *position);
let was_already_hovering =
+2 -2
View File
@@ -154,7 +154,7 @@ impl JsonRpcService {
break;
}
log::trace!("JSON-RPC: received message: {message}");
log::trace!("JSON-RPC: received {} bytes", message.len());
if let Err(e) = Self::handle_message(
&transport,
&message,
@@ -319,7 +319,7 @@ impl JsonRpcService {
method: String,
params: Value,
) -> Result<Value> {
log::trace!("Sending request {request_id}: {method}: {params}");
log::trace!("Sending request {request_id}: {method}");
let request = Request {
jsonrpc: JSON_RPC_VERSION,
+4 -13
View File
@@ -433,11 +433,7 @@ pub trait Setting {
};
match <Self::Value as SettingsValue>::from_file_value(&json_value) {
Some(val) => {
log::debug!(
"Loaded {} from settings file; value: {:?}",
Self::setting_name(),
val
);
log::debug!("Loaded {} from settings file", Self::setting_name());
return Some(val);
}
None => {
@@ -453,11 +449,7 @@ pub trait Setting {
match serde_json::from_str(&value) {
Ok(val) => {
log::debug!(
"Loaded {} from user defaults; value: {:?}",
Self::setting_name(),
val
);
log::debug!("Loaded {} from user defaults", Self::setting_name());
Some(val)
}
Err(err) => {
@@ -516,10 +508,9 @@ pub trait Setting {
if !stored_value_matches {
log::debug!(
"Writing new value of {} to storage; key: {}; value: {:?}",
"Writing new value of {} to storage; key: {}",
Self::setting_name(),
key,
value
key
);
let _ = preferences.write_value_with_hierarchy(
key,
+1 -5
View File
@@ -254,11 +254,7 @@ macro_rules! define_setting {
},
None => {
let default_value = Self::default_value();
log::debug!(
"Initializing {} to default value: {:?}",
Self::setting_name(),
default_value
);
log::debug!("Initializing {} to its default value", Self::setting_name());
Self {
inner: default_value,
is_explicitly_set: false,