Skip to content

Commit 1e96786

Browse files
committed
fix: initialize gui logging output
1 parent a985b76 commit 1e96786

5 files changed

Lines changed: 156 additions & 2 deletions

File tree

agent-diva-gui/src-tauri/src/lib.rs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ mod process_utils;
77
mod shutdown_manager;
88
mod tray;
99

10+
use agent_diva_core::config::schema::LoggingConfig;
11+
use agent_diva_core::config::ConfigLoader;
1012
use app_state::AgentState;
1113
use embedded_server::EmbeddedGatewayHandle;
1214
use gateway_status::GatewayStatus;
1315
use shutdown_manager::ShutdownManager;
16+
use std::path::{Path, PathBuf};
17+
use std::sync::OnceLock;
1418
use std::sync::{Arc, Mutex};
1519
use tauri::Manager;
1620
use tokio::sync::Mutex as AsyncMutex;
1721

22+
static LOGGING_INITIALIZED: OnceLock<()> = OnceLock::new();
23+
1824
/// Tracks completion of frontend/backend setup for splash screen.
1925
struct SplashState {
2026
frontend_done: bool,
@@ -29,8 +35,50 @@ fn should_manage_gateway_lifecycle() -> bool {
2935
!cfg!(debug_assertions)
3036
}
3137

38+
fn config_loader() -> ConfigLoader {
39+
match std::env::var("AGENT_DIVA_CONFIG_DIR") {
40+
Ok(path) if !path.trim().is_empty() => ConfigLoader::with_dir(expand_user_path(&path)),
41+
_ => ConfigLoader::new(),
42+
}
43+
}
44+
45+
fn expand_user_path(path: &str) -> PathBuf {
46+
if let Some(rest) = path.strip_prefix("~/") {
47+
if let Some(home) = dirs::home_dir() {
48+
return home.join(rest);
49+
}
50+
}
51+
PathBuf::from(path)
52+
}
53+
54+
fn resolve_configured_path(path: &str, config_dir: &Path) -> PathBuf {
55+
let expanded = expand_user_path(path);
56+
if expanded.is_absolute() {
57+
expanded
58+
} else {
59+
config_dir.join(expanded)
60+
}
61+
}
62+
63+
fn resolve_logging_config(mut config: LoggingConfig, config_dir: &Path) -> LoggingConfig {
64+
config.dir = resolve_configured_path(&config.dir, config_dir)
65+
.to_string_lossy()
66+
.to_string();
67+
config
68+
}
69+
70+
fn init_gui_logging() {
71+
LOGGING_INITIALIZED.get_or_init(|| {
72+
let loader = config_loader();
73+
let config = loader.load().unwrap_or_default();
74+
let logging = resolve_logging_config(config.logging, loader.config_dir());
75+
let guard = agent_diva_core::logging::init_logging_with_terminal_output(&logging, false);
76+
Box::leak(Box::new(guard));
77+
});
78+
}
79+
3280
fn build_gateway_runtime_config() -> agent_diva_manager::GatewayRuntimeConfig {
33-
let loader = agent_diva_core::config::ConfigLoader::new();
81+
let loader = config_loader();
3482
let config = loader.load().unwrap_or_default();
3583
let runtime = agent_diva_cli::cli_runtime::CliRuntime::from_paths(
3684
None,
@@ -155,6 +203,8 @@ fn set_splash_complete(
155203

156204
#[cfg_attr(mobile, tauri::mobile_entry_point)]
157205
pub fn run() {
206+
init_gui_logging();
207+
158208
tauri::Builder::default()
159209
.plugin(tauri_plugin_opener::init())
160210
.plugin(tauri_plugin_store::Builder::new().build())
@@ -319,8 +369,13 @@ pub fn run() {
319369

320370
#[cfg(test)]
321371
mod tests {
322-
use super::{close_action, should_manage_gateway_lifecycle, CloseAction, ExitTrigger};
372+
use super::{
373+
close_action, resolve_configured_path, resolve_logging_config,
374+
should_manage_gateway_lifecycle, CloseAction, ExitTrigger,
375+
};
323376
use crate::shutdown_manager::ShutdownManager;
377+
use agent_diva_core::config::schema::LoggingConfig;
378+
use tempfile::TempDir;
324379

325380
#[test]
326381
fn gateway_lifecycle_is_disabled_in_debug_mode() {
@@ -370,4 +425,37 @@ mod tests {
370425
assert!(manager.begin_shutdown());
371426
assert!(!manager.begin_shutdown());
372427
}
428+
429+
#[test]
430+
fn relative_log_dir_resolves_under_config_dir() {
431+
let config_dir = TempDir::new().unwrap();
432+
433+
let path = resolve_configured_path("logs", config_dir.path());
434+
435+
assert_eq!(path, config_dir.path().join("logs"));
436+
}
437+
438+
#[test]
439+
fn absolute_log_dir_is_preserved() {
440+
let config_dir = TempDir::new().unwrap();
441+
let absolute = config_dir.path().join("custom-logs");
442+
443+
let path = resolve_configured_path(&absolute.to_string_lossy(), config_dir.path());
444+
445+
assert_eq!(path, absolute);
446+
}
447+
448+
#[test]
449+
fn logging_config_uses_resolved_log_dir() {
450+
let config_dir = TempDir::new().unwrap();
451+
let mut logging = LoggingConfig::default();
452+
logging.dir = "logs".to_string();
453+
454+
let resolved = resolve_logging_config(logging, config_dir.path());
455+
456+
assert_eq!(
457+
resolved.dir,
458+
config_dir.path().join("logs").to_string_lossy().to_string()
459+
);
460+
}
373461
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Acceptance
2+
3+
## User Steps
4+
5+
1. Launch `agent-diva-gui`.
6+
2. Open Settings > General.
7+
3. Wait for the embedded gateway to start.
8+
4. Refresh the Gateway Logs panel.
9+
10+
## Expected Result
11+
12+
- The configured logs directory contains a current `gateway.log.<date>` file.
13+
- The Gateway Logs panel displays recent embedded gateway log lines instead of staying empty.
14+
- Existing CLI log output behavior is unchanged.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Release
2+
3+
## Method
4+
5+
Ship with the next GUI build. No migration is required because the existing `logging` config schema is unchanged.
6+
7+
## Notes
8+
9+
- Relative `logging.dir` values continue to be interpreted relative to the Agent Diva config directory in the GUI log viewer.
10+
- The GUI logger now writes to the same resolved directory.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Summary
2+
3+
## What Changed
4+
5+
- Initialized GUI process logging before the Tauri builder starts.
6+
- Resolved the GUI log directory with the same config-relative rules used by the log viewer.
7+
- Kept the tracing non-blocking worker guard alive for the full GUI process lifetime.
8+
9+
## Impact
10+
11+
- Embedded gateway logs can be written to the configured file directory.
12+
- Settings > General > Gateway Logs can read the same files created by the embedded gateway.
13+
- CLI logging behavior is unchanged.
14+
15+
## Root Cause
16+
17+
The GUI embedded gateway bypassed the CLI entrypoint, so it never called the shared tracing initialization used by `agent-diva-cli`. The log viewer also reads config-relative log paths, so GUI logging must initialize with the same resolved directory.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Verification
2+
3+
## Commands
4+
5+
- `cargo fmt --check -p agent-diva-gui`
6+
- `cargo check -p agent-diva-gui`
7+
- `cargo test -p agent-diva-gui`
8+
- `cargo test -p agent-diva-gui embedded_gateway_serves_health_endpoint -- --nocapture`
9+
- `cargo test -p agent-diva-gui log_dir`
10+
11+
## Result
12+
13+
- `cargo fmt --check -p agent-diva-gui`: passed.
14+
- `cargo check -p agent-diva-gui`: passed.
15+
- `cargo test -p agent-diva-gui`: failed because existing `embedded_server::tests::embedded_gateway_serves_health_endpoint` did not become ready and returned Windows TCP connection refused. 20 tests passed, including the new logging path tests.
16+
- `cargo test -p agent-diva-gui embedded_gateway_serves_health_endpoint -- --nocapture`: failed with the same connection refused health check result.
17+
- `cargo test -p agent-diva-gui log_dir`: passed, 3 logging directory tests passed.
18+
19+
## Manual Smoke
20+
21+
1. Start the GUI in Tauri runtime.
22+
2. Confirm the embedded gateway starts.
23+
3. Confirm `gateway.log.<date>` appears under the configured logging directory.
24+
4. Open Settings > General > Gateway Logs and refresh.
25+
5. Confirm recent embedded gateway log lines are visible.

0 commit comments

Comments
 (0)