Skip to content

Commit

Permalink
tracing added to server
Browse files Browse the repository at this point in the history
  • Loading branch information
ahau-square committed Jan 6, 2025
1 parent 697b1e2 commit 926e412
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 113 deletions.
2 changes: 2 additions & 0 deletions crates/goose-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ rust_decimal_macros = "1.36.0"
tracing = "0.1"
chrono = "0.4"
parking_lot = "0.12.3"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json", "time"] }
tracing-appender = "0.2"

[dev-dependencies]
tempfile = "3"
Expand Down
102 changes: 102 additions & 0 deletions crates/goose-cli/src/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use anyhow::{Context, Result};
use std::fs;
use std::path::PathBuf;
use tracing_appender::rolling::Rotation;
use tracing_subscriber::{
fmt,
Layer,
layer::SubscriberExt,
util::SubscriberInitExt,
EnvFilter,
Registry,
filter::LevelFilter,
};

use goose::tracing::langfuse_layer;

/// Returns the directory where log files should be stored.
/// Creates the directory structure if it doesn't exist.
fn get_log_directory() -> Result<PathBuf> {
let home = std::env::var("HOME").context("HOME environment variable not set")?;
let base_log_dir = PathBuf::from(home)
.join(".config")
.join("goose")
.join("logs")
.join("cli"); // Add cli-specific subdirectory

// Create date-based subdirectory
let now = chrono::Local::now();
let date_dir = base_log_dir.join(now.format("%Y-%m-%d").to_string());

// Ensure log directory exists
fs::create_dir_all(&date_dir).context("Failed to create log directory")?;

Ok(date_dir)
}

/// Sets up the logging infrastructure for the application.
/// This includes:
/// - File-based logging with JSON formatting (DEBUG level)
/// - Console output for development (INFO level)
/// - Optional Langfuse integration (DEBUG level)
pub fn setup_logging() -> Result<()> {
// Set up file appender for goose module logs
let log_dir = get_log_directory()?;
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S").to_string();

// Create non-rolling file appender for detailed logs
let file_appender = tracing_appender::rolling::RollingFileAppender::new(
Rotation::NEVER,
log_dir,
&format!("goose_{}.log", timestamp),
);

// Create JSON file logging layer with all logs (DEBUG and above)
let file_layer = fmt::layer()
.with_target(true)
.with_level(true)
.with_writer(file_appender)
.with_ansi(false)
.with_file(true)
.pretty();

// Create console logging layer for development - INFO and above only
let console_layer = fmt::layer()
.with_target(true)
.with_level(true)
.with_ansi(true)
.with_file(true)
.with_line_number(true)
.pretty();

// Base filter
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
// Set default levels for different modules
EnvFilter::new("")
// Set goose module to INFO only
.add_directive("goose=debug".parse().unwrap())
// Set goose-cli to INFO
.add_directive("goose_cli=info".parse().unwrap())
// Set everything else to WARN
.add_directive(LevelFilter::WARN.into())
});

// Build the subscriber with required layers
let subscriber = Registry::default()
.with(file_layer.with_filter(env_filter)) // Gets all logs
.with(console_layer.with_filter(LevelFilter::INFO)); // Controls log levels

// Initialize with Langfuse if available
if let Some(langfuse) = langfuse_layer::create_langfuse_observer() {
subscriber
.with(langfuse.with_filter(LevelFilter::DEBUG))
.try_init()
.context("Failed to set global subscriber")?;
} else {
subscriber
.try_init()
.context("Failed to set global subscriber")?;
}

Ok(())
}
5 changes: 3 additions & 2 deletions crates/goose-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod agents;
mod profile;
mod prompt;
pub mod session;
mod logging;

mod systems;

Expand All @@ -17,7 +18,7 @@ use commands::session::build_session;
use commands::version::print_version;
use profile::has_no_profiles;
use std::io::{self, Read};
use goose::logging::setup_logging;
use logging::setup_logging;

mod log_usage;

Expand Down Expand Up @@ -196,7 +197,7 @@ enum CliProviderVariant {

#[tokio::main]
async fn main() -> Result<()> {
setup_logging()?;
setup_logging();

let cli = Cli::parse();

Expand Down
5 changes: 3 additions & 2 deletions crates/goose-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
futures = "0.3"
tracing = "0.1"
tracing-subscriber = "0.3"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json", "time"] }
tracing-appender = "0.2"
tokio-stream = "0.1"
anyhow = "1.0"
bytes = "1.5"
Expand All @@ -34,4 +35,4 @@ path = "src/main.rs"
[dev-dependencies]
serial_test = "3.2.0"
tower = "0.5"
async-trait = "0.1"
async-trait = "0.1"
103 changes: 103 additions & 0 deletions crates/goose-server/src/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use anyhow::{Context, Result};
use std::fs;
use std::path::PathBuf;
use tracing_appender::rolling::Rotation;
use tracing_subscriber::{
fmt,
Layer,
layer::SubscriberExt,
util::SubscriberInitExt,
EnvFilter,
Registry,
filter::LevelFilter,
};

use goose::tracing::langfuse_layer;

/// Returns the directory where log files should be stored.
/// Creates the directory structure if it doesn't exist.
fn get_log_directory() -> Result<PathBuf> {
let home = std::env::var("HOME").context("HOME environment variable not set")?;
let base_log_dir = PathBuf::from(home)
.join(".config")
.join("goose")
.join("logs")
.join("server"); // Add server-specific subdirectory

// Create date-based subdirectory
let now = chrono::Local::now();
let date_dir = base_log_dir.join(now.format("%Y-%m-%d").to_string());

// Ensure log directory exists
fs::create_dir_all(&date_dir).context("Failed to create log directory")?;

Ok(date_dir)
}

/// Sets up the logging infrastructure for the application.
/// This includes:
/// - File-based logging with JSON formatting (DEBUG level)
/// - Console output for development (INFO level)
/// - Optional Langfuse integration (DEBUG level)
pub fn setup_logging() -> Result<()> {
// Set up file appender for goose module logs
let log_dir = get_log_directory()?;
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S").to_string();

// Create non-rolling file appender for detailed logs
let file_appender = tracing_appender::rolling::RollingFileAppender::new(
Rotation::NEVER,
log_dir,
&format!("goosed_{}.log", timestamp),
);

// Create JSON file logging layer
let file_layer = fmt::layer()
.with_target(true)
.with_level(true)
.with_writer(file_appender)
.with_ansi(false)
.with_file(true);

// Create console logging layer for development - INFO and above only
let console_layer = fmt::layer()
.with_target(true)
.with_level(true)
.with_ansi(true)
.with_file(true)
.with_line_number(true)
.pretty();

// Base filter for all logging
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
// Set default levels for different modules
EnvFilter::new("")
// Set goose module to INFO only
.add_directive("goose=info".parse().unwrap())
// Set goose-server to INFO
.add_directive("goose_server=info".parse().unwrap())
// Set tower-http to INFO for request logging
.add_directive("tower_http=info".parse().unwrap())
// Set everything else to WARN
.add_directive(LevelFilter::WARN.into())
});

// Build the subscriber with required layers
let subscriber = Registry::default()
.with(file_layer)
.with(console_layer.with_filter(env_filter));

// Initialize with Langfuse if available
if let Some(langfuse) = langfuse_layer::create_langfuse_observer() {
subscriber
.with(langfuse.with_filter(LevelFilter::DEBUG))
.try_init()
.context("Failed to set global subscriber")?;
} else {
subscriber
.try_init()
.context("Failed to set global subscriber")?;
}

Ok(())
}
5 changes: 3 additions & 2 deletions crates/goose-server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod configuration;
mod error;
mod logging;
mod routes;
mod state;

Expand All @@ -9,7 +10,7 @@ use tracing::info;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize tracing for logging
tracing_subscriber::fmt::init();
logging::setup_logging()?;

// Load configuration
let settings = configuration::Settings::new()?;
Expand All @@ -34,4 +35,4 @@ async fn main() -> anyhow::Result<()> {
info!("listening on {}", listener.local_addr()?);
axum::serve(listener, app).await?;
Ok(())
}
}
4 changes: 2 additions & 2 deletions crates/goose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ libc = "=0.2.167"
lazy_static = "1.5"
kill_tree = "0.2.4"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json", "time"] }
tracing-appender = "0.2"
tracing-subscriber = "0.3"


keyring = { version = "3.6.1", features = [
"apple-native",
Expand Down
6 changes: 3 additions & 3 deletions crates/goose/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ impl Agent {
let system_tool_call = ToolCall::new(tool_name, call.arguments);
let result = system.call(system_tool_call.clone()).await;

tracing::debug!("input"=serde_json::to_string(&system_tool_call).unwrap(),
"output"=serde_json::to_string(&result).unwrap(),
debug!("input"=serde_json::to_string(&system_tool_call).unwrap(),
"output"=serde_json::to_string(&result).unwrap(),
);

result
Expand Down Expand Up @@ -350,7 +350,7 @@ impl Agent {
.and_then(|msg| msg.content.first())
.and_then(|c| c.as_text())
{
reply_span.record("user_message", &content);
debug!("user_message"=&content);
}

let system_prompt = self.get_system_prompt()?;
Expand Down
1 change: 0 additions & 1 deletion crates/goose/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ pub mod providers;
pub mod systems;
pub mod token_counter;
pub mod tracing;
pub mod logging;
Loading

0 comments on commit 926e412

Please sign in to comment.