diff --git a/server/packages/sandbox-agent/src/agent_server_logs/mod.rs b/server/packages/sandbox-agent/src/agent_server_logs/mod.rs new file mode 100644 index 0000000..d593c76 --- /dev/null +++ b/server/packages/sandbox-agent/src/agent_server_logs/mod.rs @@ -0,0 +1,9 @@ +#[cfg(unix)] +mod unix; +#[cfg(windows)] +mod windows; + +#[cfg(unix)] +pub use unix::AgentServerLogs; +#[cfg(windows)] +pub use windows::AgentServerLogs; diff --git a/server/packages/sandbox-agent/src/agent_server_logs/unix.rs b/server/packages/sandbox-agent/src/agent_server_logs/unix.rs new file mode 100644 index 0000000..746aa76 --- /dev/null +++ b/server/packages/sandbox-agent/src/agent_server_logs/unix.rs @@ -0,0 +1,79 @@ +use std::fs::OpenOptions; +use std::path::{Path, PathBuf}; + +use sandbox_agent_error::SandboxError; +use time::{Duration, OffsetDateTime}; + +const LOG_RETENTION_DAYS: i64 = 7; + +pub struct AgentServerLogs { + base_dir: PathBuf, + agent: String, +} + +impl AgentServerLogs { + pub fn new(base_dir: PathBuf, agent: impl Into) -> Self { + Self { + base_dir, + agent: agent.into(), + } + } + + pub fn open(&self) -> Result { + let log_dir = self.base_dir.join(&self.agent); + std::fs::create_dir_all(&log_dir).map_err(|err| SandboxError::StreamError { + message: err.to_string(), + })?; + + let now = OffsetDateTime::now_utc(); + let file_name = format!( + "{}-{:04}-{:02}-{:02}.log", + self.agent, + now.year(), + now.month() as u8, + now.day() + ); + let path = log_dir.join(file_name); + self.prune_logs(&log_dir, now)?; + + let file = OpenOptions::new() + .create(true) + .append(true) + .open(&path) + .map_err(|err| SandboxError::StreamError { + message: err.to_string(), + })?; + + eprintln!("{} server logs: {}", self.agent, path.display()); + Ok(file.into()) + } + + fn prune_logs(&self, log_dir: &Path, now: OffsetDateTime) -> Result<(), SandboxError> { + let retention = Duration::days(LOG_RETENTION_DAYS); + let cutoff = now - retention; + let entries = std::fs::read_dir(log_dir).map_err(|err| SandboxError::StreamError { + message: err.to_string(), + })?; + + for entry in entries { + let entry = match entry { + Ok(entry) => entry, + Err(_) => continue, + }; + let metadata = match entry.metadata() { + Ok(metadata) => metadata, + Err(_) => continue, + }; + let modified = match metadata.modified() { + Ok(modified) => modified, + Err(_) => continue, + }; + let modified = OffsetDateTime::from(modified); + if modified < cutoff { + let _ = std::fs::remove_file(entry.path()); + } + } + + Ok(()) + } +} diff --git a/server/packages/sandbox-agent/src/agent_server_logs/windows.rs b/server/packages/sandbox-agent/src/agent_server_logs/windows.rs new file mode 100644 index 0000000..746aa76 --- /dev/null +++ b/server/packages/sandbox-agent/src/agent_server_logs/windows.rs @@ -0,0 +1,79 @@ +use std::fs::OpenOptions; +use std::path::{Path, PathBuf}; + +use sandbox_agent_error::SandboxError; +use time::{Duration, OffsetDateTime}; + +const LOG_RETENTION_DAYS: i64 = 7; + +pub struct AgentServerLogs { + base_dir: PathBuf, + agent: String, +} + +impl AgentServerLogs { + pub fn new(base_dir: PathBuf, agent: impl Into) -> Self { + Self { + base_dir, + agent: agent.into(), + } + } + + pub fn open(&self) -> Result { + let log_dir = self.base_dir.join(&self.agent); + std::fs::create_dir_all(&log_dir).map_err(|err| SandboxError::StreamError { + message: err.to_string(), + })?; + + let now = OffsetDateTime::now_utc(); + let file_name = format!( + "{}-{:04}-{:02}-{:02}.log", + self.agent, + now.year(), + now.month() as u8, + now.day() + ); + let path = log_dir.join(file_name); + self.prune_logs(&log_dir, now)?; + + let file = OpenOptions::new() + .create(true) + .append(true) + .open(&path) + .map_err(|err| SandboxError::StreamError { + message: err.to_string(), + })?; + + eprintln!("{} server logs: {}", self.agent, path.display()); + Ok(file.into()) + } + + fn prune_logs(&self, log_dir: &Path, now: OffsetDateTime) -> Result<(), SandboxError> { + let retention = Duration::days(LOG_RETENTION_DAYS); + let cutoff = now - retention; + let entries = std::fs::read_dir(log_dir).map_err(|err| SandboxError::StreamError { + message: err.to_string(), + })?; + + for entry in entries { + let entry = match entry { + Ok(entry) => entry, + Err(_) => continue, + }; + let metadata = match entry.metadata() { + Ok(metadata) => metadata, + Err(_) => continue, + }; + let modified = match metadata.modified() { + Ok(modified) => modified, + Err(_) => continue, + }; + let modified = OffsetDateTime::from(modified); + if modified < cutoff { + let _ = std::fs::remove_file(entry.path()); + } + } + + Ok(()) + } +}