1use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
8#[serde(rename_all = "lowercase")]
9pub enum LogFormat {
10 #[default]
12 Pretty,
13 Json,
15 Compact,
17}
18
19#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
21#[serde(rename_all = "lowercase")]
22pub enum LogLevel {
23 Trace,
24 Debug,
25 #[default]
26 Info,
27 Warn,
28 Error,
29}
30
31impl From<LogLevel> for tracing::Level {
32 fn from(level: LogLevel) -> Self {
33 match level {
34 LogLevel::Trace => tracing::Level::TRACE,
35 LogLevel::Debug => tracing::Level::DEBUG,
36 LogLevel::Info => tracing::Level::INFO,
37 LogLevel::Warn => tracing::Level::WARN,
38 LogLevel::Error => tracing::Level::ERROR,
39 }
40 }
41}
42
43impl From<LogLevel> for tracing_subscriber::filter::LevelFilter {
44 fn from(level: LogLevel) -> Self {
45 match level {
46 LogLevel::Trace => tracing_subscriber::filter::LevelFilter::TRACE,
47 LogLevel::Debug => tracing_subscriber::filter::LevelFilter::DEBUG,
48 LogLevel::Info => tracing_subscriber::filter::LevelFilter::INFO,
49 LogLevel::Warn => tracing_subscriber::filter::LevelFilter::WARN,
50 LogLevel::Error => tracing_subscriber::filter::LevelFilter::ERROR,
51 }
52 }
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct LoggingConfig {
58 #[serde(default)]
60 pub level: LogLevel,
61
62 #[serde(default)]
64 pub format: LogFormat,
65
66 #[serde(default)]
68 pub file: Option<FileLoggingConfig>,
69
70 #[serde(default = "default_true")]
72 pub include_location: bool,
73
74 #[serde(default = "default_true")]
76 pub include_target: bool,
77
78 #[serde(default)]
81 pub filter_directives: Option<String>,
82}
83
84fn default_true() -> bool {
85 true
86}
87
88impl Default for LoggingConfig {
89 fn default() -> Self {
90 Self {
91 level: LogLevel::Info,
92 format: LogFormat::Pretty,
93 file: None,
94 include_location: true,
95 include_target: true,
96 filter_directives: None,
97 }
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct FileLoggingConfig {
104 pub directory: PathBuf,
106
107 #[serde(default = "default_prefix")]
109 pub prefix: String,
110
111 #[serde(default)]
113 pub rotation: RotationStrategy,
114}
115
116fn default_prefix() -> String {
117 "zlayer".to_string()
118}
119
120#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
122#[serde(rename_all = "lowercase")]
123pub enum RotationStrategy {
124 #[default]
126 Daily,
127 Hourly,
129 Never,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct MetricsConfig {
136 #[serde(default = "default_true")]
138 pub enabled: bool,
139
140 #[serde(default = "default_metrics_path")]
142 pub path: String,
143
144 #[serde(default)]
146 pub port: Option<u16>,
147}
148
149fn default_metrics_path() -> String {
150 "/metrics".to_string()
151}
152
153impl Default for MetricsConfig {
154 fn default() -> Self {
155 Self {
156 enabled: true,
157 path: default_metrics_path(),
158 port: None,
159 }
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct TracingConfig {
166 #[serde(default)]
168 pub enabled: bool,
169
170 #[serde(default)]
172 pub otlp_endpoint: Option<String>,
173
174 #[serde(default = "default_service_name")]
176 pub service_name: String,
177
178 #[serde(default = "default_sampling_ratio")]
180 pub sampling_ratio: f64,
181
182 #[serde(default)]
184 pub environment: Option<String>,
185
186 #[serde(default)]
188 pub batch: BatchConfig,
189
190 #[serde(default = "default_true")]
192 pub use_grpc: bool,
193}
194
195fn default_service_name() -> String {
196 "zlayer".to_string()
197}
198
199fn default_sampling_ratio() -> f64 {
200 1.0
201}
202
203fn default_max_queue_size() -> usize {
204 2048
205}
206
207fn default_scheduled_delay() -> u64 {
208 5000
209}
210
211fn default_max_export_batch_size() -> usize {
212 512
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct BatchConfig {
218 #[serde(default = "default_max_queue_size")]
220 pub max_queue_size: usize,
221
222 #[serde(default = "default_scheduled_delay")]
224 pub scheduled_delay_ms: u64,
225
226 #[serde(default = "default_max_export_batch_size")]
228 pub max_export_batch_size: usize,
229}
230
231impl Default for BatchConfig {
232 fn default() -> Self {
233 Self {
234 max_queue_size: default_max_queue_size(),
235 scheduled_delay_ms: default_scheduled_delay(),
236 max_export_batch_size: default_max_export_batch_size(),
237 }
238 }
239}
240
241impl Default for TracingConfig {
242 fn default() -> Self {
243 Self {
244 enabled: false,
245 otlp_endpoint: None,
246 service_name: default_service_name(),
247 sampling_ratio: default_sampling_ratio(),
248 environment: None,
249 batch: BatchConfig::default(),
250 use_grpc: true,
251 }
252 }
253}
254
255impl TracingConfig {
256 #[must_use]
258 pub fn from_env() -> Self {
259 Self {
260 enabled: std::env::var("OTEL_TRACES_ENABLED")
261 .map(|v| v == "true" || v == "1")
262 .unwrap_or(false),
263 otlp_endpoint: std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok(),
264 service_name: std::env::var("OTEL_SERVICE_NAME")
265 .unwrap_or_else(|_| "zlayer".to_string()),
266 sampling_ratio: std::env::var("OTEL_TRACES_SAMPLER_ARG")
267 .ok()
268 .and_then(|v| v.parse().ok())
269 .unwrap_or(1.0),
270 environment: std::env::var("DEPLOYMENT_ENVIRONMENT").ok(),
271 batch: BatchConfig::default(),
272 use_grpc: std::env::var("OTEL_EXPORTER_OTLP_PROTOCOL")
273 .map(|v| v != "http/protobuf")
274 .unwrap_or(true),
275 }
276 }
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize, Default)]
281pub struct ObservabilityConfig {
282 #[serde(default)]
284 pub logging: LoggingConfig,
285
286 #[serde(default)]
288 pub metrics: MetricsConfig,
289
290 #[serde(default)]
292 pub tracing: TracingConfig,
293}