use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Settings {
#[serde(default)]
pub working_dir: Option<PathBuf>,
#[serde(default = "default_log_level")]
pub log_level: String,
#[serde(default)]
pub json_logs: bool,
#[serde(default)]
pub log_file: Option<PathBuf>,
#[serde(default = "default_max_concurrent")]
pub max_concurrent_jobs: usize,
#[serde(default = "default_shell")]
pub shell: String,
#[serde(default = "default_shell_args")]
pub shell_args: Vec<String>,
#[serde(default = "default_watch_config")]
pub watch_config: bool,
#[serde(default)]
pub pid_file: Option<PathBuf>,
#[cfg(feature = "metrics")]
#[serde(default)]
pub metrics_addr: Option<String>,
#[serde(default = "default_history_size")]
pub history_size: usize,
#[serde(default = "default_timezone")]
pub timezone: String,
#[serde(default = "default_grace_period")]
pub shutdown_grace_period: u64,
}
fn default_log_level() -> String {
"info".to_string()
}
fn default_max_concurrent() -> usize {
10
}
fn default_shell() -> String {
if cfg!(windows) {
"cmd".to_string()
} else {
"/bin/sh".to_string()
}
}
fn default_shell_args() -> Vec<String> {
if cfg!(windows) {
vec!["/C".to_string()]
} else {
vec!["-c".to_string()]
}
}
fn default_watch_config() -> bool {
true
}
fn default_history_size() -> usize {
1000
}
fn default_timezone() -> String {
"UTC".to_string()
}
fn default_grace_period() -> u64 {
30
}
impl Default for Settings {
fn default() -> Self {
Self {
working_dir: None,
log_level: default_log_level(),
json_logs: false,
log_file: None,
max_concurrent_jobs: default_max_concurrent(),
shell: default_shell(),
shell_args: default_shell_args(),
watch_config: default_watch_config(),
pid_file: None,
#[cfg(feature = "metrics")]
metrics_addr: None,
history_size: default_history_size(),
timezone: default_timezone(),
shutdown_grace_period: default_grace_period(),
}
}
}
impl Settings {
pub fn shell_command(&self) -> (&str, &[String]) {
(&self.shell, &self.shell_args)
}
pub fn tracing_level(&self) -> tracing::Level {
match self.log_level.to_lowercase().as_str() {
"trace" => tracing::Level::TRACE,
"debug" => tracing::Level::DEBUG,
"info" => tracing::Level::INFO,
"warn" | "warning" => tracing::Level::WARN,
"error" => tracing::Level::ERROR,
_ => tracing::Level::INFO,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_settings() {
let settings = Settings::default();
assert_eq!(settings.log_level, "info");
assert_eq!(settings.max_concurrent_jobs, 10);
assert!(settings.watch_config);
}
#[test]
fn test_tracing_level() {
let mut settings = Settings::default();
settings.log_level = "debug".to_string();
assert_eq!(settings.tracing_level(), tracing::Level::DEBUG);
settings.log_level = "error".to_string();
assert_eq!(settings.tracing_level(), tracing::Level::ERROR);
settings.log_level = "invalid".to_string();
assert_eq!(settings.tracing_level(), tracing::Level::INFO);
}
}