use std::time::Duration;
use serde::{Deserialize, Serialize};
use forge_core::LogLevel;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObservabilityConfig {
pub enabled: bool,
pub database_url: Option<String>,
pub pool_size: u32,
pub pool_timeout: Duration,
pub metrics: MetricsConfig,
pub logs: LogsConfig,
pub traces: TracesConfig,
pub export: ExportConfig,
}
impl Default for ObservabilityConfig {
fn default() -> Self {
Self {
enabled: true,
database_url: None,
pool_size: 10,
pool_timeout: Duration::from_secs(5),
metrics: MetricsConfig::default(),
logs: LogsConfig::default(),
traces: TracesConfig::default(),
export: ExportConfig::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetricsConfig {
pub interval: Duration,
pub raw_retention: Duration,
pub downsampled_1m: Duration,
pub downsampled_5m: Duration,
pub downsampled_1h: Duration,
pub buffer_size: usize,
pub flush_interval: Duration,
}
impl Default for MetricsConfig {
fn default() -> Self {
Self {
interval: Duration::from_secs(10),
raw_retention: Duration::from_secs(3600), downsampled_1m: Duration::from_secs(86400), downsampled_5m: Duration::from_secs(604800), downsampled_1h: Duration::from_secs(7776000), buffer_size: 10000,
flush_interval: Duration::from_secs(10),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogsConfig {
pub level: LogLevel,
pub retention: Duration,
pub slow_query_threshold: Duration,
pub async_writes: bool,
pub buffer_size: usize,
}
impl Default for LogsConfig {
fn default() -> Self {
Self {
level: LogLevel::Info,
retention: Duration::from_secs(604800), slow_query_threshold: Duration::from_millis(100),
async_writes: true,
buffer_size: 5000,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TracesConfig {
pub sample_rate: f64,
pub retention: Duration,
pub always_trace_errors: bool,
}
impl Default for TracesConfig {
fn default() -> Self {
Self {
sample_rate: 1.0,
retention: Duration::from_secs(86400), always_trace_errors: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportConfig {
pub destinations: Vec<ExportDestination>,
pub otlp: Option<OtlpConfig>,
pub prometheus: Option<PrometheusConfig>,
}
impl Default for ExportConfig {
fn default() -> Self {
Self {
destinations: vec![ExportDestination::Postgres],
otlp: None,
prometheus: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ExportDestination {
Postgres,
Otlp,
Prometheus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OtlpConfig {
pub endpoint: String,
pub protocol: String,
pub headers: std::collections::HashMap<String, String>,
pub metrics: bool,
pub logs: bool,
pub traces: bool,
pub trace_sample_rate: f64,
pub always_export_errors: bool,
}
impl Default for OtlpConfig {
fn default() -> Self {
Self {
endpoint: "http://localhost:4317".to_string(),
protocol: "grpc".to_string(),
headers: std::collections::HashMap::new(),
metrics: true,
logs: true,
traces: true,
trace_sample_rate: 1.0,
always_export_errors: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrometheusConfig {
pub enabled: bool,
pub path: String,
}
impl Default for PrometheusConfig {
fn default() -> Self {
Self {
enabled: false,
path: "/metrics".to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_observability_config_default() {
let config = ObservabilityConfig::default();
assert!(config.enabled);
assert!(config.database_url.is_none());
assert_eq!(config.pool_size, 10);
}
#[test]
fn test_metrics_config_default() {
let config = MetricsConfig::default();
assert_eq!(config.interval, Duration::from_secs(10));
assert_eq!(config.buffer_size, 10000);
}
#[test]
fn test_logs_config_default() {
let config = LogsConfig::default();
assert_eq!(config.level, LogLevel::Info);
assert!(config.async_writes);
}
#[test]
fn test_traces_config_default() {
let config = TracesConfig::default();
assert_eq!(config.sample_rate, 1.0);
assert!(config.always_trace_errors);
}
#[test]
fn test_export_config_default() {
let config = ExportConfig::default();
assert_eq!(config.destinations, vec![ExportDestination::Postgres]);
}
}