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
79fn default_true() -> bool {
80 true
81}
82
83impl Default for LoggingConfig {
84 fn default() -> Self {
85 Self {
86 level: LogLevel::Info,
87 format: LogFormat::Pretty,
88 file: None,
89 include_location: true,
90 include_target: true,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct FileLoggingConfig {
98 pub directory: PathBuf,
100
101 #[serde(default = "default_prefix")]
103 pub prefix: String,
104
105 #[serde(default)]
107 pub rotation: RotationStrategy,
108}
109
110fn default_prefix() -> String {
111 "zlayer".to_string()
112}
113
114#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
116#[serde(rename_all = "lowercase")]
117pub enum RotationStrategy {
118 #[default]
120 Daily,
121 Hourly,
123 Never,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct MetricsConfig {
130 #[serde(default = "default_true")]
132 pub enabled: bool,
133
134 #[serde(default = "default_metrics_path")]
136 pub path: String,
137
138 #[serde(default)]
140 pub port: Option<u16>,
141}
142
143fn default_metrics_path() -> String {
144 "/metrics".to_string()
145}
146
147impl Default for MetricsConfig {
148 fn default() -> Self {
149 Self {
150 enabled: true,
151 path: default_metrics_path(),
152 port: None,
153 }
154 }
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct TracingConfig {
160 #[serde(default)]
162 pub enabled: bool,
163
164 #[serde(default)]
166 pub otlp_endpoint: Option<String>,
167
168 #[serde(default = "default_service_name")]
170 pub service_name: String,
171
172 #[serde(default = "default_sampling_ratio")]
174 pub sampling_ratio: f64,
175
176 #[serde(default)]
178 pub environment: Option<String>,
179
180 #[serde(default)]
182 pub batch: BatchConfig,
183
184 #[serde(default = "default_true")]
186 pub use_grpc: bool,
187}
188
189fn default_service_name() -> String {
190 "zlayer".to_string()
191}
192
193fn default_sampling_ratio() -> f64 {
194 1.0
195}
196
197fn default_max_queue_size() -> usize {
198 2048
199}
200
201fn default_scheduled_delay() -> u64 {
202 5000
203}
204
205fn default_max_export_batch_size() -> usize {
206 512
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct BatchConfig {
212 #[serde(default = "default_max_queue_size")]
214 pub max_queue_size: usize,
215
216 #[serde(default = "default_scheduled_delay")]
218 pub scheduled_delay_ms: u64,
219
220 #[serde(default = "default_max_export_batch_size")]
222 pub max_export_batch_size: usize,
223}
224
225impl Default for BatchConfig {
226 fn default() -> Self {
227 Self {
228 max_queue_size: default_max_queue_size(),
229 scheduled_delay_ms: default_scheduled_delay(),
230 max_export_batch_size: default_max_export_batch_size(),
231 }
232 }
233}
234
235impl Default for TracingConfig {
236 fn default() -> Self {
237 Self {
238 enabled: false,
239 otlp_endpoint: None,
240 service_name: default_service_name(),
241 sampling_ratio: default_sampling_ratio(),
242 environment: None,
243 batch: BatchConfig::default(),
244 use_grpc: true,
245 }
246 }
247}
248
249impl TracingConfig {
250 pub fn from_env() -> Self {
252 Self {
253 enabled: std::env::var("OTEL_TRACES_ENABLED")
254 .map(|v| v == "true" || v == "1")
255 .unwrap_or(false),
256 otlp_endpoint: std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok(),
257 service_name: std::env::var("OTEL_SERVICE_NAME")
258 .unwrap_or_else(|_| "zlayer".to_string()),
259 sampling_ratio: std::env::var("OTEL_TRACES_SAMPLER_ARG")
260 .ok()
261 .and_then(|v| v.parse().ok())
262 .unwrap_or(1.0),
263 environment: std::env::var("DEPLOYMENT_ENVIRONMENT").ok(),
264 batch: BatchConfig::default(),
265 use_grpc: std::env::var("OTEL_EXPORTER_OTLP_PROTOCOL")
266 .map(|v| v != "http/protobuf")
267 .unwrap_or(true),
268 }
269 }
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize, Default)]
274pub struct ObservabilityConfig {
275 #[serde(default)]
277 pub logging: LoggingConfig,
278
279 #[serde(default)]
281 pub metrics: MetricsConfig,
282
283 #[serde(default)]
285 pub tracing: TracingConfig,
286}