Files
tkmind_go/crates/goose-cli/src/logging.rs
T
Rodolfo Olivieri 4de5fcdff8 refactor(logging): consolidate logging setup into shared helper in goose crate (#8817)
Signed-off-by: Rodolfo Olivieri <rolivier@redhat.com>
Signed-off-by: Douwe Osinga <douwe@squareup.com>
Co-authored-by: Douwe Osinga <douwe@squareup.com>
2026-05-13 18:35:41 +00:00

142 lines
4.6 KiB
Rust

use anyhow::Result;
use std::sync::Once;
// Used to ensure we only set up tracing once
static INIT: Once = Once::new();
/// Sets up the logging infrastructure for the CLI.
/// Logs go to a JSON file only (no console output).
pub fn setup_logging(name: Option<&str>) -> Result<()> {
setup_logging_internal(name, false)
}
fn setup_logging_internal(name: Option<&str>, force: bool) -> Result<()> {
let mut result = Ok(());
let mut setup = || {
result = (|| {
use tracing_subscriber::util::SubscriberInitExt;
let config = goose::logging::LoggingConfig {
component: "cli",
name,
extra_directives: &["goose_cli=info"],
console: false,
json: true,
};
let subscriber = goose::logging::build_logging_subscriber(&config)?;
if force {
let _guard = subscriber.set_default();
tracing::warn!("Test log entry from setup");
tracing::info!("Another test log entry from setup");
std::thread::sleep(std::time::Duration::from_millis(100));
Ok(())
} else {
subscriber
.try_init()
.map_err(|e| anyhow::anyhow!("Failed to set global subscriber: {}", e))?;
Ok(())
}
})();
};
if force {
setup();
} else {
INIT.call_once(setup);
}
result
}
#[cfg(test)]
mod tests {
use goose::tracing::langfuse_layer;
use std::env;
use tempfile::TempDir;
fn setup_temp_home() -> TempDir {
let temp_dir = TempDir::new().unwrap();
if cfg!(windows) {
env::set_var("USERPROFILE", temp_dir.path());
} else {
env::set_var("HOME", temp_dir.path());
}
temp_dir
}
#[test]
fn test_log_directory_creation() {
let _temp_dir = setup_temp_home();
let log_dir = goose::logging::prepare_log_directory("cli", true).unwrap();
assert!(log_dir.exists());
assert!(log_dir.is_dir());
let path_components: Vec<_> = log_dir.components().collect();
assert!(path_components.iter().any(|c| c.as_os_str() == "goose"));
assert!(path_components.iter().any(|c| c.as_os_str() == "logs"));
assert!(path_components.iter().any(|c| c.as_os_str() == "cli"));
}
#[tokio::test]
async fn test_langfuse_layer_creation() {
let _temp_dir = setup_temp_home();
let original_vars = [
("LANGFUSE_PUBLIC_KEY", env::var("LANGFUSE_PUBLIC_KEY").ok()),
("LANGFUSE_SECRET_KEY", env::var("LANGFUSE_SECRET_KEY").ok()),
("LANGFUSE_URL", env::var("LANGFUSE_URL").ok()),
(
"LANGFUSE_INIT_PROJECT_PUBLIC_KEY",
env::var("LANGFUSE_INIT_PROJECT_PUBLIC_KEY").ok(),
),
(
"LANGFUSE_INIT_PROJECT_SECRET_KEY",
env::var("LANGFUSE_INIT_PROJECT_SECRET_KEY").ok(),
),
];
for (var, _) in &original_vars {
env::remove_var(var);
}
assert!(langfuse_layer::create_langfuse_observer().is_none());
env::set_var("LANGFUSE_PUBLIC_KEY", "test_public_key");
env::set_var("LANGFUSE_SECRET_KEY", "test_secret_key");
assert!(langfuse_layer::create_langfuse_observer().is_some());
env::remove_var("LANGFUSE_PUBLIC_KEY");
env::remove_var("LANGFUSE_SECRET_KEY");
env::set_var("LANGFUSE_INIT_PROJECT_PUBLIC_KEY", "test_public_key");
env::set_var("LANGFUSE_INIT_PROJECT_SECRET_KEY", "test_secret_key");
assert!(langfuse_layer::create_langfuse_observer().is_some());
env::remove_var("LANGFUSE_INIT_PROJECT_PUBLIC_KEY");
assert!(langfuse_layer::create_langfuse_observer().is_none());
for (var, value) in original_vars {
match value {
Some(val) => env::set_var(var, val),
None => env::remove_var(var),
}
}
}
#[tokio::test]
async fn test_default_filter_avoids_debug_by_default() {
// The shared helper honours RUST_LOG; without it the defaults apply.
// We just smoke-check that building the subscriber doesn't panic.
let _temp_dir = setup_temp_home();
let config = goose::logging::LoggingConfig {
component: "cli-test",
name: None,
extra_directives: &["goose_cli=info"],
console: false,
json: true,
};
assert!(goose::logging::build_logging_subscriber(&config).is_ok());
}
}