1use std::env;
2use std::path::PathBuf;
3use std::time::Duration;
4
5use serde::{Deserialize, Serialize};
6
7use crate::error::{OtellError, Result};
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct Config {
11 pub db_path: PathBuf,
12 pub otlp_grpc_addr: String,
13 pub otlp_http_addr: String,
14 pub query_tcp_addr: String,
15 pub query_http_addr: String,
16 pub uds_path: PathBuf,
17 pub retention_ttl: Duration,
18 pub retention_max_bytes: u64,
19 pub write_batch_size: usize,
20 pub write_flush_ms: u64,
21 pub forward_otlp_endpoint: Option<String>,
22 pub forward_otlp_protocol: String,
23}
24
25impl Default for Config {
26 fn default() -> Self {
27 let home = env::var("HOME").unwrap_or_else(|_| ".".to_string());
28 let xdg_runtime = env::var("XDG_RUNTIME_DIR").ok();
29 let data_home = env::var("XDG_DATA_HOME").ok();
30
31 let data_root = data_home
32 .map(PathBuf::from)
33 .unwrap_or_else(|| PathBuf::from(home).join(".local/share"));
34
35 let uds_path = xdg_runtime
36 .map(PathBuf::from)
37 .unwrap_or_else(|| data_root.join("otell"))
38 .join("otell.sock");
39
40 Self {
41 db_path: data_root.join("otell/otell.duckdb"),
42 otlp_grpc_addr: "127.0.0.1:4317".to_string(),
43 otlp_http_addr: "127.0.0.1:4318".to_string(),
44 query_tcp_addr: "127.0.0.1:1777".to_string(),
45 query_http_addr: "127.0.0.1:1778".to_string(),
46 uds_path,
47 retention_ttl: Duration::from_secs(60 * 60 * 24),
48 retention_max_bytes: 2 * 1024 * 1024 * 1024,
49 write_batch_size: 2048,
50 write_flush_ms: 200,
51 forward_otlp_endpoint: None,
52 forward_otlp_protocol: "grpc".to_string(),
53 }
54 }
55}
56
57impl Config {
58 pub fn from_env() -> Result<Self> {
59 let mut cfg = Self::default();
60
61 if let Ok(v) = env::var("OTELL_DB_PATH") {
62 cfg.db_path = PathBuf::from(v);
63 }
64 if let Ok(v) = env::var("OTELL_OTLP_GRPC_ADDR") {
65 cfg.otlp_grpc_addr = v;
66 }
67 if let Ok(v) = env::var("OTELL_OTLP_HTTP_ADDR") {
68 cfg.otlp_http_addr = v;
69 }
70 if let Ok(v) = env::var("OTELL_QUERY_TCP_ADDR") {
71 cfg.query_tcp_addr = v;
72 }
73 if let Ok(v) = env::var("OTELL_QUERY_HTTP_ADDR") {
74 cfg.query_http_addr = v;
75 }
76 if let Ok(v) = env::var("OTELL_QUERY_UDS_PATH") {
77 cfg.uds_path = PathBuf::from(v);
78 }
79 if let Ok(v) = env::var("OTELL_RETENTION_TTL") {
80 cfg.retention_ttl = humantime::parse_duration(&v)
81 .map_err(|e| OtellError::Config(format!("bad OTELL_RETENTION_TTL: {e}")))?;
82 }
83 if let Ok(v) = env::var("OTELL_RETENTION_MAX_BYTES") {
84 cfg.retention_max_bytes = v
85 .parse::<u64>()
86 .map_err(|e| OtellError::Config(format!("bad OTELL_RETENTION_MAX_BYTES: {e}")))?;
87 }
88 if let Ok(v) = env::var("OTELL_FORWARD_OTLP_ENDPOINT") {
89 cfg.forward_otlp_endpoint = Some(v);
90 }
91 if let Ok(v) = env::var("OTELL_FORWARD_OTLP_PROTOCOL") {
92 cfg.forward_otlp_protocol = v;
93 }
94
95 Ok(cfg)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn default_has_expected_ports() {
105 let cfg = Config::default();
106 assert_eq!(cfg.otlp_grpc_addr, "127.0.0.1:4317");
107 assert_eq!(cfg.otlp_http_addr, "127.0.0.1:4318");
108 assert_eq!(cfg.query_tcp_addr, "127.0.0.1:1777");
109 assert_eq!(cfg.query_http_addr, "127.0.0.1:1778");
110 }
111
112 #[test]
113 fn default_has_retention() {
114 let cfg = Config::default();
115 assert_eq!(cfg.retention_ttl, Duration::from_secs(86_400));
116 assert!(cfg.retention_max_bytes > 1024 * 1024);
117 }
118}