dmsc/observability/
mod.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Observability Module
19//! 
20//! This module provides comprehensive observability capabilities for DMSC, including distributed tracing
21//! and metrics collection. It follows modern observability best practices to help monitor, debug, and
22//! optimize DMSC applications.
23//! 
24//! ## Key Components
25//! 
26//! - **DMSCObservabilityModule**: Main observability module
27//! - **DMSCTracer**: Distributed tracing implementation
28//! - **DMSCMetricsRegistry**: Metrics collection and aggregation
29//! - **DMSCObservabilityConfig**: Configuration for observability features
30//! - **DMSCObservabilityData**: Exported observability data structure
31//! 
32//! ## Design Principles
33//! 
34//! 1. **Separation of Concerns**: Tracing and metrics are separate but integrated components
35//! 2. **Configurable**: All features can be enabled/disabled and configured at runtime
36//! 3. **Non-intrusive**: Designed to be easy to integrate without disrupting application logic
37//! 4. **Performance-focused**: Optimized for low overhead in production environments
38//! 5. **Standard-compliant**: Follows W3C Trace Context standard for distributed tracing
39//! 6. **Prometheus-compatible**: Metrics are exported in Prometheus format
40//! 7. **Service Module Integration**: Implements the `ServiceModule` trait for seamless integration
41//! 
42//! ## Usage
43//! 
44//! ```rust
45//! use dmsc::prelude::*;
46//! 
47//! fn example() -> DMSCResult<()> {
48//!     // Create a DMSC app builder
49//!     let mut builder = DMSCAppBuilder::new();
50//!     
51//!     // Configure observability
52//!     let observability_config = DMSCObservabilityConfig {
53//!         tracing_enabled: true,
54//!         metrics_enabled: true,
55//!         tracing_sampling_rate: 0.5, // 50% sampling rate
56//!         metrics_window_size_secs: 300,
57//!         metrics_bucket_size_secs: 10,
58//!     };
59//!     
60//!     // Add observability module to the app
61//!     let observability_module = DMSCObservabilityModule::new()
62//!         .with_config(observability_config);
63//!     
64//!     builder.add_module(Box::new(observability_module));
65//!     
66//!     // Build and run the app
67//!     let mut app = builder.build()?;
68//!     app.run()?;
69//!     
70//!     Ok(())
71//! }
72//! ```
73
74mod metrics;
75pub mod tracing;
76pub mod propagation;
77#[cfg(feature = "observability")]
78pub mod prometheus;
79#[cfg(feature = "system_info")]
80mod metrics_collector;
81pub mod grafana;
82
83use std::sync::Arc;
84use serde::{Serialize, Deserialize};
85
86pub use tracing::{DMSCTracer, DMSCTraceId, DMSCSpanId, DMSCSpan, DMSCSpanKind, DMSCSpanStatus, DMSCTracingContext, DMSCSamplingStrategy};
87pub use metrics::{DMSCMetricsRegistry, DMSCMetric, DMSCMetricConfig, DMSCMetricType, DMSCWindowStats, DMSCMetricSample};
88pub use propagation::{DMSCTraceContext, DMSCBaggage, DMSCContextCarrier, W3CTracePropagator};
89#[cfg(feature = "system_info")]
90pub use metrics_collector::{DMSCSystemMetricsCollector, DMSCSystemMetrics, DMSCCPUMetrics, DMSCMemoryMetrics, DMSCDiskMetrics, DMSCNetworkMetrics};
91
92use crate::core::{DMSCResult, DMSCServiceContext};
93
94
95/// Main observability module for DMSC.
96/// 
97/// This module provides distributed tracing and metrics collection capabilities, following modern
98/// observability best practices. It implements the `ServiceModule` trait for seamless integration
99/// with the DMSC application lifecycle.
100#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
101pub struct DMSCObservabilityModule {
102    /// Distributed tracer instance
103    tracer: Option<Arc<DMSCTracer>>,
104    /// Metrics registry for collecting and aggregating metrics
105    metrics_registry: Option<Arc<DMSCMetricsRegistry>>,
106    /// Configuration for observability features
107    config: DMSCObservabilityConfig,
108}
109
110/// Configuration for the observability module.
111/// 
112/// This struct defines the configuration options for tracing and metrics collection in DMSC.
113#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct DMSCObservabilityConfig {
116    /// Whether distributed tracing is enabled
117    pub tracing_enabled: bool,
118    /// Whether metrics collection is enabled
119    pub metrics_enabled: bool,
120    /// Sampling rate for distributed tracing (0.0 to 1.0)
121    pub tracing_sampling_rate: f64,
122    /// Sampling strategy for distributed tracing
123    pub tracing_sampling_strategy: String,
124    /// Window size for metrics aggregation in seconds
125    pub metrics_window_size_secs: u64,
126    /// Bucket size for metrics aggregation in seconds
127    pub metrics_bucket_size_secs: u64,
128}
129
130impl Default for DMSCObservabilityConfig {
131    /// Returns the default configuration for observability.
132    /// 
133    /// Default values:
134    /// - tracing_enabled: true
135    /// - metrics_enabled: true
136    /// - tracing_sampling_rate: 0.1 (10% sampling)
137    /// - tracing_sampling_strategy: "rate" (fixed rate sampling)
138    /// - metrics_window_size_secs: 300 (5 minutes)
139    /// - metrics_bucket_size_secs: 10 (10 seconds)
140    fn default() -> Self {
141        Self {
142            tracing_enabled: true,
143            metrics_enabled: true,
144            tracing_sampling_rate: 0.1, // 10% sampling by default
145            tracing_sampling_strategy: "rate".to_string(), // fixed rate sampling by default
146            metrics_window_size_secs: 300, // 5 minutes
147            metrics_bucket_size_secs: 10,  // 10 seconds
148        }
149    }
150}
151
152#[cfg(feature = "pyo3")]
153/// Python methods for DMSCObservabilityConfig
154#[pyo3::prelude::pymethods]
155impl DMSCObservabilityConfig {
156    #[new]
157    fn py_new() -> Self {
158        Self::default()
159    }
160    
161    /// Set tracing enabled flag from Python
162    fn set_tracing_enabled(&mut self, tracing_enabled: bool) {
163        self.tracing_enabled = tracing_enabled;
164    }
165    
166    /// Get tracing enabled flag from Python
167    fn get_tracing_enabled(&self) -> bool {
168        self.tracing_enabled
169    }
170    
171    /// Set metrics enabled flag from Python
172    fn set_metrics_enabled(&mut self, metrics_enabled: bool) {
173        self.metrics_enabled = metrics_enabled;
174    }
175    
176    /// Get metrics enabled flag from Python
177    fn get_metrics_enabled(&self) -> bool {
178        self.metrics_enabled
179    }
180    
181    /// Set tracing sampling rate from Python
182    fn set_tracing_sampling_rate(&mut self, tracing_sampling_rate: f64) -> pyo3::PyResult<()>
183    {
184        if tracing_sampling_rate < 0.0 || tracing_sampling_rate > 1.0 {
185            return Err(pyo3::exceptions::PyValueError::new_err("Tracing sampling rate must be between 0.0 and 1.0"));
186        }
187        self.tracing_sampling_rate = tracing_sampling_rate;
188        Ok(())
189    }
190    
191    /// Get tracing sampling rate from Python
192    fn get_tracing_sampling_rate(&self) -> f64 {
193        self.tracing_sampling_rate
194    }
195    
196    /// Set tracing sampling strategy from Python
197    fn set_tracing_sampling_strategy(&mut self, tracing_sampling_strategy: String) {
198        self.tracing_sampling_strategy = tracing_sampling_strategy;
199    }
200    
201    /// Get tracing sampling strategy from Python
202    fn get_tracing_sampling_strategy(&self) -> String {
203        self.tracing_sampling_strategy.clone()
204    }
205    
206    /// Set metrics window size in seconds from Python
207    fn set_metrics_window_size_secs(&mut self, metrics_window_size_secs: u64) {
208        self.metrics_window_size_secs = metrics_window_size_secs;
209    }
210    
211    /// Get metrics window size in seconds from Python
212    fn get_metrics_window_size_secs(&self) -> u64 {
213        self.metrics_window_size_secs
214    }
215    
216    /// Set metrics bucket size in seconds from Python
217    fn set_metrics_bucket_size_secs(&mut self, metrics_bucket_size_secs: u64) {
218        self.metrics_bucket_size_secs = metrics_bucket_size_secs;
219    }
220    
221    /// Get metrics bucket size in seconds from Python
222    fn get_metrics_bucket_size_secs(&self) -> u64 {
223        self.metrics_bucket_size_secs
224    }
225}
226
227impl Default for DMSCObservabilityModule {
228    fn default() -> Self {
229        Self::new()
230    }
231}
232
233impl DMSCObservabilityModule {
234    /// Creates a new observability module with default configuration.
235    /// 
236    /// # Returns
237    /// 
238    /// A new `DMSCObservabilityModule` instance with default configuration
239    pub fn new() -> Self {
240        Self {
241            tracer: None,
242            metrics_registry: None,
243            config: DMSCObservabilityConfig::default(),
244        }
245    }
246    
247    /// Configures the observability module with custom settings.
248    /// 
249    /// # Parameters
250    /// 
251    /// - `config`: The custom configuration to apply
252    /// 
253    /// # Returns
254    /// 
255    /// The updated `DMSCObservabilityModule` instance
256    pub fn with_config(mut self, config: DMSCObservabilityConfig) -> Self {
257        self.config = config;
258        self
259    }
260    
261    /// Initializes tracing with the configured sampling strategy.
262    /// 
263    /// This method sets up the distributed tracer with the specified sampling strategy.
264    fn init_tracing(&mut self) {
265        if self.config.tracing_enabled {
266            // Initialize tracer with the configured rate
267            // Note: In a real implementation, we'd use the appropriate strategy
268            tracing::init_tracer(self.config.tracing_sampling_rate);
269        }
270    }
271    
272    /// Initializes the metrics registry.
273    /// 
274    /// This method creates and configures the metrics registry for collecting and aggregating metrics.
275    fn init_metrics(&mut self) {
276        if self.config.metrics_enabled {
277            let registry = Arc::new(DMSCMetricsRegistry::new());
278            self.metrics_registry = Some(registry);
279        }
280    }
281    
282    /// Creates common service metrics.
283    /// 
284    /// This method registers standard service metrics including:
285    /// - Request duration histogram
286    /// - Request counter
287    /// - Error counter
288    /// - Active connections gauge
289    /// - Service startup time
290    /// - Module initialization time
291    /// - Request queue length
292    /// - Middleware execution time
293    /// - Cache metrics (hits, misses, entries, memory usage)
294    /// - Database query time
295    /// 
296    /// # Returns
297    /// 
298    /// A `DMSCResult<()>` indicating success or failure
299    fn create_service_metrics(&self) -> DMSCResult<()> {
300        if let Some(registry) = &self.metrics_registry {
301            // Request duration histogram
302            let request_duration_config = DMSCMetricConfig {
303                metric_type: DMSCMetricType::Histogram,
304                name: "dms_request_duration_seconds".to_string(),
305                help: "Request duration in seconds".to_string(),
306                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0], // seconds
307                quantiles: vec![0.5, 0.9, 0.95, 0.99],
308                max_age: std::time::Duration::from_secs(300),
309                age_buckets: 5,
310            };
311            
312            let request_duration_metric = Arc::new(DMSCMetric::new(request_duration_config));
313            registry.register(request_duration_metric)?;
314            
315            // Request counter
316            let request_counter_config = DMSCMetricConfig {
317                metric_type: DMSCMetricType::Counter,
318                name: "dms_requests_total".to_string(),
319                help: "Total number of requests".to_string(),
320                buckets: vec![],
321                quantiles: vec![],
322                max_age: std::time::Duration::from_secs(0),
323                age_buckets: 0,
324            };
325            
326            let request_counter_metric = Arc::new(DMSCMetric::new(request_counter_config));
327            registry.register(request_counter_metric)?;
328            
329            // Error counter
330            let error_counter_config = DMSCMetricConfig {
331                metric_type: DMSCMetricType::Counter,
332                name: "dms_errors_total".to_string(),
333                help: "Total number of errors".to_string(),
334                buckets: vec![],
335                quantiles: vec![],
336                max_age: std::time::Duration::from_secs(0),
337                age_buckets: 0,
338            };
339            
340            let error_counter_metric = Arc::new(DMSCMetric::new(error_counter_config));
341            registry.register(error_counter_metric)?;
342            
343            // Active connections gauge
344            let connections_gauge_config = DMSCMetricConfig {
345                metric_type: DMSCMetricType::Gauge,
346                name: "dms_active_connections".to_string(),
347                help: "Number of active connections".to_string(),
348                buckets: vec![],
349                quantiles: vec![],
350                max_age: std::time::Duration::from_secs(0),
351                age_buckets: 0,
352            };
353            
354            let connections_gauge_metric = Arc::new(DMSCMetric::new(connections_gauge_config));
355            registry.register(connections_gauge_metric)?;
356            
357            // Service startup time gauge
358            let startup_time_config = DMSCMetricConfig {
359                metric_type: DMSCMetricType::Gauge,
360                name: "dms_service_startup_time_seconds".to_string(),
361                help: "Service startup time in seconds".to_string(),
362                buckets: vec![],
363                quantiles: vec![],
364                max_age: std::time::Duration::from_secs(0),
365                age_buckets: 0,
366            };
367            
368            let startup_time_metric = Arc::new(DMSCMetric::new(startup_time_config));
369            registry.register(startup_time_metric)?;
370            
371            // Module initialization time histogram
372            let module_init_config = DMSCMetricConfig {
373                metric_type: DMSCMetricType::Histogram,
374                name: "dms_module_init_time_seconds".to_string(),
375                help: "Module initialization time in seconds".to_string(),
376                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0],
377                quantiles: vec![0.5, 0.9, 0.95, 0.99],
378                max_age: std::time::Duration::from_secs(300),
379                age_buckets: 5,
380            };
381            
382            let module_init_metric = Arc::new(DMSCMetric::new(module_init_config));
383            registry.register(module_init_metric)?;
384            
385            // Request queue length gauge
386            let queue_length_config = DMSCMetricConfig {
387                metric_type: DMSCMetricType::Gauge,
388                name: "dms_request_queue_length".to_string(),
389                help: "Request queue length".to_string(),
390                buckets: vec![],
391                quantiles: vec![],
392                max_age: std::time::Duration::from_secs(0),
393                age_buckets: 0,
394            };
395            
396            let queue_length_metric = Arc::new(DMSCMetric::new(queue_length_config));
397            registry.register(queue_length_metric)?;
398            
399            // Middleware execution time histogram
400            let middleware_time_config = DMSCMetricConfig {
401                metric_type: DMSCMetricType::Histogram,
402                name: "dms_middleware_duration_seconds".to_string(),
403                help: "Middleware execution time in seconds".to_string(),
404                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5],
405                quantiles: vec![0.5, 0.9, 0.95, 0.99],
406                max_age: std::time::Duration::from_secs(300),
407                age_buckets: 5,
408            };
409            
410            let middleware_time_metric = Arc::new(DMSCMetric::new(middleware_time_config));
411            registry.register(middleware_time_metric)?;
412            
413            // Cache metrics
414            // Cache hit counter
415            let cache_hit_config = DMSCMetricConfig {
416                metric_type: DMSCMetricType::Counter,
417                name: "dms_cache_hits_total".to_string(),
418                help: "Total number of cache hits".to_string(),
419                buckets: vec![],
420                quantiles: vec![],
421                max_age: std::time::Duration::from_secs(0),
422                age_buckets: 0,
423            };
424            
425            let cache_hit_metric = Arc::new(DMSCMetric::new(cache_hit_config));
426            registry.register(cache_hit_metric)?;
427            
428            // Cache miss counter
429            let cache_miss_config = DMSCMetricConfig {
430                metric_type: DMSCMetricType::Counter,
431                name: "dms_cache_misses_total".to_string(),
432                help: "Total number of cache misses".to_string(),
433                buckets: vec![],
434                quantiles: vec![],
435                max_age: std::time::Duration::from_secs(0),
436                age_buckets: 0,
437            };
438            
439            let cache_miss_metric = Arc::new(DMSCMetric::new(cache_miss_config));
440            registry.register(cache_miss_metric)?;
441            
442            // Cache entries gauge
443            let cache_entries_config = DMSCMetricConfig {
444                metric_type: DMSCMetricType::Gauge,
445                name: "dms_cache_entries".to_string(),
446                help: "Number of cache entries".to_string(),
447                buckets: vec![],
448                quantiles: vec![],
449                max_age: std::time::Duration::from_secs(0),
450                age_buckets: 0,
451            };
452            
453            let cache_entries_metric = Arc::new(DMSCMetric::new(cache_entries_config));
454            registry.register(cache_entries_metric)?;
455            
456            // Cache memory usage gauge
457            let cache_memory_config = DMSCMetricConfig {
458                metric_type: DMSCMetricType::Gauge,
459                name: "dms_cache_memory_usage_bytes".to_string(),
460                help: "Cache memory usage in bytes".to_string(),
461                buckets: vec![],
462                quantiles: vec![],
463                max_age: std::time::Duration::from_secs(0),
464                age_buckets: 0,
465            };
466            
467            let cache_memory_metric = Arc::new(DMSCMetric::new(cache_memory_config));
468            registry.register(cache_memory_metric)?;
469            
470            // Cache eviction counter
471            let cache_eviction_config = DMSCMetricConfig {
472                metric_type: DMSCMetricType::Counter,
473                name: "dms_cache_evictions_total".to_string(),
474                help: "Total number of cache evictions".to_string(),
475                buckets: vec![],
476                quantiles: vec![],
477                max_age: std::time::Duration::from_secs(0),
478                age_buckets: 0,
479            };
480            
481            let cache_eviction_metric = Arc::new(DMSCMetric::new(cache_eviction_config));
482            registry.register(cache_eviction_metric)?;
483            
484            // Database metrics
485            // Database query time histogram
486            let db_query_config = DMSCMetricConfig {
487                metric_type: DMSCMetricType::Histogram,
488                name: "dms_db_query_duration_seconds".to_string(),
489                help: "Database query execution time in seconds".to_string(),
490                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0],
491                quantiles: vec![0.5, 0.9, 0.95, 0.99],
492                max_age: std::time::Duration::from_secs(300),
493                age_buckets: 5,
494            };
495            
496            let db_query_metric = Arc::new(DMSCMetric::new(db_query_config));
497            registry.register(db_query_metric)?;
498            
499            // Database active connections gauge
500            let db_active_connections_config = DMSCMetricConfig {
501                metric_type: DMSCMetricType::Gauge,
502                name: "dms_db_active_connections".to_string(),
503                help: "Number of active database connections".to_string(),
504                buckets: vec![],
505                quantiles: vec![],
506                max_age: std::time::Duration::from_secs(0),
507                age_buckets: 0,
508            };
509            
510            let db_active_connections_metric = Arc::new(DMSCMetric::new(db_active_connections_config));
511            registry.register(db_active_connections_metric)?;
512            
513            // Database idle connections gauge
514            let db_idle_connections_config = DMSCMetricConfig {
515                metric_type: DMSCMetricType::Gauge,
516                name: "dms_db_idle_connections".to_string(),
517                help: "Number of idle database connections".to_string(),
518                buckets: vec![],
519                quantiles: vec![],
520                max_age: std::time::Duration::from_secs(0),
521                age_buckets: 0,
522            };
523            
524            let db_idle_connections_metric = Arc::new(DMSCMetric::new(db_idle_connections_config));
525            registry.register(db_idle_connections_metric)?;
526            
527            // Database connection timeouts counter
528            let db_timeout_config = DMSCMetricConfig {
529                metric_type: DMSCMetricType::Counter,
530                name: "dms_db_connection_timeouts_total".to_string(),
531                help: "Total number of database connection timeouts".to_string(),
532                buckets: vec![],
533                quantiles: vec![],
534                max_age: std::time::Duration::from_secs(0),
535                age_buckets: 0,
536            };
537            
538            let db_timeout_metric = Arc::new(DMSCMetric::new(db_timeout_config));
539            registry.register(db_timeout_metric)?;
540            
541            // Database errors counter
542            let db_errors_config = DMSCMetricConfig {
543                metric_type: DMSCMetricType::Counter,
544                name: "dms_db_errors_total".to_string(),
545                help: "Total number of database errors".to_string(),
546                buckets: vec![],
547                quantiles: vec![],
548                max_age: std::time::Duration::from_secs(0),
549                age_buckets: 0,
550            };
551            
552            let db_errors_metric = Arc::new(DMSCMetric::new(db_errors_config));
553            registry.register(db_errors_metric)?;
554            
555            // Database transactions counter
556            let db_transactions_config = DMSCMetricConfig {
557                metric_type: DMSCMetricType::Counter,
558                name: "dms_db_transactions_total".to_string(),
559                help: "Total number of database transactions".to_string(),
560                buckets: vec![],
561                quantiles: vec![],
562                max_age: std::time::Duration::from_secs(0),
563                age_buckets: 0,
564            };
565            
566            let db_transactions_metric = Arc::new(DMSCMetric::new(db_transactions_config));
567            registry.register(db_transactions_metric)?;
568            
569            // Database transaction commits counter
570            let db_commits_config = DMSCMetricConfig {
571                metric_type: DMSCMetricType::Counter,
572                name: "dms_db_transaction_commits_total".to_string(),
573                help: "Total number of database transaction commits".to_string(),
574                buckets: vec![],
575                quantiles: vec![],
576                max_age: std::time::Duration::from_secs(0),
577                age_buckets: 0,
578            };
579            
580            let db_commits_metric = Arc::new(DMSCMetric::new(db_commits_config));
581            registry.register(db_commits_metric)?;
582            
583            // Database transaction rollbacks counter
584            let db_rollbacks_config = DMSCMetricConfig {
585                metric_type: DMSCMetricType::Counter,
586                name: "dms_db_transaction_rollbacks_total".to_string(),
587                help: "Total number of database transaction rollbacks".to_string(),
588                buckets: vec![],
589                quantiles: vec![],
590                max_age: std::time::Duration::from_secs(0),
591                age_buckets: 0,
592            };
593            
594            let db_rollbacks_metric = Arc::new(DMSCMetric::new(db_rollbacks_config));
595            registry.register(db_rollbacks_metric)?;
596        }
597        
598        Ok(())
599    }
600    
601    /// Exports observability data.
602    /// 
603    /// This method collects and returns the current observability data, including metrics in Prometheus
604    /// format and information about active traces and spans.
605    /// 
606    /// # Returns
607    /// 
608    /// A `DMSCObservabilityData` struct containing the exported observability data
609    pub fn export_data(&self) -> DMSCObservabilityData {
610        DMSCObservabilityData {
611            metrics: {
612                #[cfg(feature = "observability")]
613                {
614                    self.metrics_registry.as_ref().map(|r| r.export_prometheus()).unwrap_or_default()
615                }
616                #[cfg(not(feature = "observability"))]
617                {
618                    String::default()
619                }
620            },
621            active_traces: self.tracer.as_ref().map(|_| tracing::tracer().map(|t| t.active_trace_count()).unwrap_or(0)).unwrap_or(0),
622            active_spans: self.tracer.as_ref().map(|_| tracing::tracer().map(|t| t.active_span_count()).unwrap_or(0)).unwrap_or(0),
623        }
624    }
625}
626
627/// Exported observability data structure.
628/// 
629/// This struct represents the observability data that can be exported from the DMSC system,
630/// including metrics in Prometheus format and information about active traces and spans.
631#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
632#[derive(Debug, Clone, Serialize, Deserialize)]
633pub struct DMSCObservabilityData {
634    /// Metrics data in Prometheus format
635    pub metrics: String,
636    /// Number of active traces
637    pub active_traces: usize,
638    /// Number of active spans
639    pub active_spans: usize,
640}
641
642#[cfg(feature = "pyo3")]
643/// Python methods for DMSCObservabilityData
644#[pyo3::prelude::pymethods]
645impl DMSCObservabilityData {
646    /// Create new observability data from Python
647    #[new]
648    fn py_new(metrics: String, active_traces: usize, active_spans: usize) -> Self {
649        Self {
650            metrics,
651            active_traces,
652            active_spans,
653        }
654    }
655    
656    /// Get metrics data from Python
657    #[pyo3(name = "get_metrics")]
658    fn get_metrics_impl(&self) -> String {
659        self.metrics.clone()
660    }
661    
662    /// Get active traces count from Python
663    #[pyo3(name = "get_active_traces")]
664    fn get_active_traces_impl(&self) -> usize {
665        self.active_traces
666    }
667    
668    /// Get active spans count from Python
669    #[pyo3(name = "get_active_spans")]
670    fn get_active_spans_impl(&self) -> usize {
671        self.active_spans
672    }
673}
674
675#[cfg(feature = "pyo3")]
676#[pyo3::prelude::pymethods]
677impl DMSCObservabilityModule {
678    fn get_metrics(&self) -> String {
679        format!("ObservabilityModule with config: {:?}", self.config)
680    }
681}
682
683#[async_trait::async_trait]
684impl crate::core::DMSCModule for DMSCObservabilityModule {
685    /// Returns the name of the observability module.
686    /// 
687    /// # Returns
688    /// 
689    /// The module name as a string
690    fn name(&self) -> &str {
691        "DMSC.Observability"
692    }
693    
694    /// Indicates whether the observability module is critical.
695    /// 
696    /// The observability module is non-critical, meaning that if it fails to initialize or operate,
697    /// it should not break the entire application. This allows the core functionality to continue
698    /// even if observability features are unavailable.
699    /// 
700    /// # Returns
701    /// 
702    /// `false` since observability is non-critical
703    fn is_critical(&self) -> bool {
704        false // Non-critical, should not break the app if observability fails
705    }
706    
707    /// Initializes the observability module.
708    /// 
709    /// This method performs the following steps:
710    /// 1. Loads configuration from the service context
711    /// 2. Initializes tracing with the configured sampling rate
712    /// 3. Initializes the metrics registry
713    /// 4. Creates common service metrics
714    /// 5. Registers lifecycle hooks for automatic metrics collection
715    /// 6. Logs initialization completion
716    /// 
717    /// # Parameters
718    /// 
719    /// - `ctx`: The service context containing configuration and other services
720    /// 
721    /// # Returns
722    /// 
723    /// A `DMSCResult<()>` indicating success or failure
724    async fn init(&mut self, ctx: &mut DMSCServiceContext) -> DMSCResult<()> {
725        // Load configuration
726        let binding = ctx.config();
727        let cfg = binding.config();
728        
729        self.config = DMSCObservabilityConfig {
730            tracing_enabled: cfg.get_bool("observability.tracing_enabled").unwrap_or(true),
731            metrics_enabled: cfg.get_bool("observability.metrics_enabled").unwrap_or(true),
732            tracing_sampling_rate: cfg.get_f32("observability.tracing_sampling_rate")
733                .unwrap_or(0.1)
734                .max(0.0)
735                .min(1.0) as f64,
736            tracing_sampling_strategy: cfg.get_str("observability.tracing_sampling_strategy")
737                .unwrap_or("rate")
738                .to_string(),
739            metrics_window_size_secs: cfg.get_u64("observability.metrics_window_size_secs")
740                .unwrap_or(300)
741                .max(1),
742            metrics_bucket_size_secs: cfg.get_u64("observability.metrics_bucket_size_secs")
743                .unwrap_or(10)
744                .max(1),
745        };
746        
747        // Initialize components
748        self.init_tracing();
749        self.init_metrics();
750        self.create_service_metrics()?;
751        
752        // Register lifecycle hooks
753        let hooks: &mut crate::hooks::DMSCHookBus = ctx.hooks_mut();
754        
755        // Hook into request lifecycle for automatic metrics collection
756        hooks.register(
757            crate::hooks::DMSCHookKind::Startup,
758            "dms.observability.lifecycle".to_string(),
759            |_ctx, _event: &crate::hooks::DMSCHookEvent| {
760                // Could add automatic span creation here
761                Ok(())
762            },
763        );
764        
765        let logger = ctx.logger();
766        logger.info("DMSC.Observability", "Observability module initialized")?;
767        
768        Ok(())
769    }
770    
771    /// Performs cleanup after the application has shut down.
772    /// 
773    /// This method exports the final observability data and logs information about active traces
774    /// and spans at the time of shutdown.
775    /// 
776    /// # Parameters
777    /// 
778    /// - `ctx`: The service context containing the logger service
779    /// 
780    /// # Returns
781    /// 
782    /// A `DMSCResult<()>` indicating success or failure
783    async fn after_shutdown(&mut self, ctx: &mut DMSCServiceContext) -> DMSCResult<()> {
784        // Export final observability data
785        let data = self.export_data();
786        
787        let logger = ctx.logger();
788        logger.info("DMSC.Observability", format!("Final observability data: {} active traces, {} active spans", 
789            data.active_traces, data.active_spans))?;
790        
791        Ok(())
792    }
793}