Skip to main content

wae_observability/
lib.rs

1//! WAE Observability - 可观测性服务抽象层
2//!
3//! 提供统一的可观测性能力抽象,包括健康检查、指标收集、日志记录和分布式追踪。
4//!
5//! 深度融合 tokio 运行时,所有 API 都是异步优先设计。
6//! 微服务架构友好,支持 HTTP 集成、Prometheus、OpenTelemetry 等特性。
7
8#![warn(missing_docs)]
9
10pub mod health;
11
12#[cfg(feature = "metrics")]
13pub mod metrics;
14
15#[cfg(feature = "otlp")]
16pub mod tracing;
17
18#[cfg(feature = "profiling")]
19pub mod profiling;
20
21#[cfg(feature = "json-log")]
22pub mod logging;
23
24use serde::{Deserialize, Serialize};
25use std::collections::HashMap;
26use wae_types::WaeError;
27
28#[cfg(feature = "json-log")]
29use ::tracing::Level;
30
31#[cfg(any(feature = "metrics", feature = "health", feature = "profiling"))]
32use std::sync::Arc;
33
34/// 可观测性操作结果类型
35pub type ObservabilityResult<T> = Result<T, WaeError>;
36
37/// 健康状态枚举
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
39pub enum HealthStatus {
40    /// 服务健康
41    #[default]
42    Passing,
43    /// 服务警告
44    Warning,
45    /// 服务失败
46    Critical,
47}
48
49/// 健康检查结果
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct HealthCheck {
52    /// 检查名称
53    pub name: String,
54    /// 健康状态
55    pub status: HealthStatus,
56    /// 检查详情
57    pub details: Option<String>,
58    /// 检查时间戳
59    pub timestamp: i64,
60}
61
62impl HealthCheck {
63    /// 创建新的健康检查
64    pub fn new(name: String, status: HealthStatus) -> Self {
65        Self { name, status, details: None, timestamp: chrono::Utc::now().timestamp() }
66    }
67
68    /// 设置检查详情
69    pub fn with_details(mut self, details: String) -> Self {
70        self.details = Some(details);
71        self
72    }
73}
74
75/// 健康检查聚合结果
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct HealthReport {
78    /// 整体健康状态
79    pub overall: HealthStatus,
80    /// 各个检查项
81    pub checks: Vec<HealthCheck>,
82}
83
84impl HealthReport {
85    /// 创建新的健康报告
86    pub fn new(checks: Vec<HealthCheck>) -> Self {
87        let overall = checks.iter().fold(HealthStatus::Passing, |acc, check| match (acc, check.status) {
88            (HealthStatus::Critical, _) | (_, HealthStatus::Critical) => HealthStatus::Critical,
89            (HealthStatus::Warning, _) | (_, HealthStatus::Warning) => HealthStatus::Warning,
90            _ => HealthStatus::Passing,
91        });
92        Self { overall, checks }
93    }
94}
95
96/// 健康检查器 trait
97#[async_trait::async_trait]
98pub trait HealthChecker: Send + Sync {
99    /// 执行健康检查
100    async fn check(&self) -> HealthCheck;
101}
102
103/// 日志输出目标
104#[cfg(feature = "json-log")]
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
106pub enum LogOutput {
107    /// 输出到标准输出
108    #[default]
109    Stdout,
110    /// 输出到标准错误
111    Stderr,
112    /// 输出到测试用的 writer(用于测试)
113    Test,
114}
115
116/// JSON 日志配置
117#[cfg(feature = "json-log")]
118#[derive(Debug, Clone)]
119pub struct JsonLogConfig {
120    /// 日志级别
121    pub level: Level,
122    /// 日志输出目标
123    pub output: LogOutput,
124    /// 是否包含目标信息
125    pub include_target: bool,
126    /// 是否包含时间戳
127    pub include_timestamp: bool,
128}
129
130#[cfg(feature = "json-log")]
131impl Default for JsonLogConfig {
132    fn default() -> Self {
133        Self { level: Level::INFO, output: LogOutput::Stdout, include_target: true, include_timestamp: true }
134    }
135}
136
137/// OTLP 导出配置
138#[cfg(feature = "otlp")]
139#[derive(Debug, Clone)]
140pub struct OtlpConfig {
141    /// OTLP 端点地址
142    pub endpoint: String,
143    /// 服务名称
144    pub service_name: String,
145    /// 服务版本
146    pub service_version: String,
147    /// 采样比率 (0.0-1.0)
148    pub sample_ratio: f64,
149    /// 是否启用
150    pub enabled: bool,
151}
152
153#[cfg(feature = "otlp")]
154impl Default for OtlpConfig {
155    fn default() -> Self {
156        Self {
157            endpoint: "http://localhost:4317".to_string(),
158            service_name: "wae-service".to_string(),
159            service_version: "0.1.0".to_string(),
160            sample_ratio: 1.0,
161            enabled: false,
162        }
163    }
164}
165
166/// 可观测性服务配置
167#[derive(Debug, Clone)]
168pub struct ObservabilityConfig {
169    /// 服务名称
170    pub service_name: String,
171    /// 服务版本
172    pub service_version: String,
173    /// 启用健康检查
174    pub enable_health: bool,
175    /// 启用指标收集
176    pub enable_metrics: bool,
177    /// 启用 JSON 日志
178    pub enable_json_log: bool,
179    /// 启用 OTLP 导出
180    pub enable_otlp: bool,
181    /// 启用性能分析
182    pub enable_profiling: bool,
183    /// JSON 日志配置
184    #[cfg(feature = "json-log")]
185    pub json_log_config: JsonLogConfig,
186    /// OTLP 配置
187    #[cfg(feature = "otlp")]
188    pub otlp_config: OtlpConfig,
189    /// Profiling 配置
190    #[cfg(feature = "profiling")]
191    pub profiling_config: profiling::ConsoleConfig,
192}
193
194impl Default for ObservabilityConfig {
195    fn default() -> Self {
196        Self {
197            service_name: "wae-service".to_string(),
198            service_version: "0.1.0".to_string(),
199            enable_health: true,
200            enable_metrics: false,
201            enable_json_log: false,
202            enable_otlp: false,
203            enable_profiling: false,
204            #[cfg(feature = "json-log")]
205            json_log_config: JsonLogConfig::default(),
206            #[cfg(feature = "otlp")]
207            otlp_config: OtlpConfig::default(),
208            #[cfg(feature = "profiling")]
209            profiling_config: profiling::ConsoleConfig::default(),
210        }
211    }
212}
213
214impl ObservabilityConfig {
215    /// 创建新的可观测性配置
216    pub fn new(service_name: String, service_version: String) -> Self {
217        Self { service_name, service_version, ..Default::default() }
218    }
219
220    /// 启用健康检查
221    pub fn with_health(mut self) -> Self {
222        self.enable_health = true;
223        self
224    }
225
226    /// 启用指标收集
227    #[cfg(feature = "metrics")]
228    pub fn with_metrics(mut self) -> Self {
229        self.enable_metrics = true;
230        self
231    }
232
233    /// 启用 JSON 日志
234    #[cfg(feature = "json-log")]
235    pub fn with_json_log(mut self) -> Self {
236        self.enable_json_log = true;
237        self
238    }
239
240    /// 启用 OTLP 导出
241    #[cfg(feature = "otlp")]
242    pub fn with_otlp(mut self) -> Self {
243        self.enable_otlp = true;
244        self
245    }
246
247    /// 启用性能分析
248    #[cfg(feature = "profiling")]
249    pub fn with_profiling(mut self) -> Self {
250        self.enable_profiling = true;
251        self
252    }
253
254    /// 设置 JSON 日志配置
255    #[cfg(feature = "json-log")]
256    pub fn with_json_log_config(mut self, config: JsonLogConfig) -> Self {
257        self.json_log_config = config;
258        self
259    }
260
261    /// 设置 OTLP 配置
262    #[cfg(feature = "otlp")]
263    pub fn with_otlp_config(mut self, config: OtlpConfig) -> Self {
264        self.otlp_config = config;
265        self
266    }
267
268    /// 设置 Profiling 配置
269    #[cfg(feature = "profiling")]
270    pub fn with_profiling_config(mut self, config: profiling::ConsoleConfig) -> Self {
271        self.profiling_config = config;
272        self
273    }
274}
275
276/// 可观测性服务
277pub struct ObservabilityService {
278    /// 服务配置
279    config: ObservabilityConfig,
280    /// 健康检查器列表
281    health_checkers: Vec<Box<dyn HealthChecker>>,
282    /// 健康检查注册器
283    #[cfg(feature = "health")]
284    health_registry: Option<Arc<health::HealthRegistry>>,
285    /// 指标注册器
286    #[cfg(feature = "metrics")]
287    metrics_registry: Option<Arc<metrics::MetricsRegistry>>,
288}
289
290impl ObservabilityService {
291    /// 创建新的可观测性服务
292    pub fn new(config: ObservabilityConfig) -> Self {
293        Self {
294            config,
295            health_checkers: Vec::new(),
296            #[cfg(feature = "health")]
297            health_registry: None,
298            #[cfg(feature = "metrics")]
299            metrics_registry: None,
300        }
301    }
302
303    /// 添加健康检查器
304    pub fn add_health_checker(&mut self, checker: Box<dyn HealthChecker>) {
305        self.health_checkers.push(checker);
306    }
307
308    /// 执行健康检查并返回报告
309    pub async fn health_check(&self) -> ObservabilityResult<HealthReport> {
310        let mut checks = Vec::with_capacity(self.health_checkers.len());
311        for checker in &self.health_checkers {
312            checks.push(checker.check().await);
313        }
314        Ok(HealthReport::new(checks))
315    }
316
317    /// 获取服务配置
318    pub fn config(&self) -> &ObservabilityConfig {
319        &self.config
320    }
321
322    /// 获取健康检查注册器
323    #[cfg(feature = "health")]
324    pub fn health_registry(&self) -> Option<&Arc<health::HealthRegistry>> {
325        self.health_registry.as_ref()
326    }
327
328    /// 获取指标注册器
329    #[cfg(feature = "metrics")]
330    pub fn metrics_registry(&self) -> Option<&Arc<metrics::MetricsRegistry>> {
331        self.metrics_registry.as_ref()
332    }
333}
334
335/// 初始化可观测性服务
336///
337/// 根据配置初始化所有启用的可观测性功能,包括日志、追踪、健康检查等。
338///
339/// # Arguments
340///
341/// * `config` - 可观测性配置
342///
343/// # Returns
344///
345/// 初始化后的可观测性服务实例
346pub fn init_observability(config: ObservabilityConfig) -> ObservabilityResult<ObservabilityService> {
347    #[cfg(feature = "json-log")]
348    let _ = config.enable_json_log;
349
350    #[cfg(feature = "otlp")]
351    let _ = config.enable_otlp;
352
353    #[cfg(feature = "profiling")]
354    if config.enable_profiling {
355        let console = profiling::TokioConsole::new();
356        console.init(&config.profiling_config);
357    }
358
359    #[allow(unused_mut)]
360    let mut service = ObservabilityService::new(config);
361
362    #[cfg(feature = "health")]
363    {
364        let registry = Arc::new(health::HealthRegistry::new());
365        service.health_registry = Some(registry);
366    }
367
368    #[cfg(feature = "metrics")]
369    if service.config.enable_metrics {
370        let registry = Arc::new(metrics::MetricsRegistry::new());
371        service.metrics_registry = Some(registry);
372    }
373
374    Ok(service)
375}
376
377/// 指标标签
378#[derive(Debug, Clone, Serialize, Deserialize)]
379pub struct MetricLabels {
380    /// 标签集合
381    labels: HashMap<String, String>,
382}
383
384impl MetricLabels {
385    /// 创建新的指标标签
386    pub fn new() -> Self {
387        Self { labels: HashMap::new() }
388    }
389
390    /// 添加标签
391    pub fn insert(&mut self, key: String, value: String) {
392        self.labels.insert(key, value);
393    }
394
395    /// 获取标签
396    pub fn get(&self, key: &str) -> Option<&String> {
397        self.labels.get(key)
398    }
399}
400
401impl Default for MetricLabels {
402    fn default() -> Self {
403        Self::new()
404    }
405}
406
407/// 基础 HTTP 健康检查器
408pub struct HttpHealthChecker {
409    /// 检查名称
410    name: String,
411    /// 检查 URL
412    url: String,
413}
414
415impl HttpHealthChecker {
416    /// 创建新的 HTTP 健康检查器
417    pub fn new(name: String, url: String) -> Self {
418        Self { name, url }
419    }
420}
421
422#[async_trait::async_trait]
423impl HealthChecker for HttpHealthChecker {
424    async fn check(&self) -> HealthCheck {
425        HealthCheck::new(self.name.clone(), HealthStatus::Passing).with_details(format!("HTTP check for {}", self.url))
426    }
427}