dmsc 0.1.9

Ri - A high-performance Rust middleware framework with modular architecture
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
//!
//! This file is part of Ri.
//! The Ri project belongs to the Dunimd Team.
//!
//! Licensed under the Apache License, Version 2.0 (the "License");
//! You may not use this file except in compliance with the License.
//! You may obtain a copy of the License at
//!
//!     http://www.apache.org/licenses/LICENSE-2.0
//!
//! Unless required by applicable law or agreed to in writing, software
//! distributed under the License is distributed on an "AS IS" BASIS,
//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//! See the License for the specific language governing permissions and
//! limitations under the License.

//! # Observability Module
//! 
//! This module provides comprehensive observability capabilities for Ri, including distributed tracing
//! and metrics collection. It follows modern observability best practices to help monitor, debug, and
//! optimize Ri applications.
//! 
//! ## Key Components
//! 
//! - **RiObservabilityModule**: Main observability module
//! - **RiTracer**: Distributed tracing implementation
//! - **RiMetricsRegistry**: Metrics collection and aggregation
//! - **RiObservabilityConfig**: Configuration for observability features
//! - **RiObservabilityData**: Exported observability data structure
//! 
//! ## Design Principles
//! 
//! 1. **Separation of Concerns**: Tracing and metrics are separate but integrated components
//! 2. **Configurable**: All features can be enabled/disabled and configured at runtime
//! 3. **Non-intrusive**: Designed to be easy to integrate without disrupting application logic
//! 4. **Performance-focused**: Optimized for low overhead in production environments
//! 5. **Standard-compliant**: Follows W3C Trace Context standard for distributed tracing
//! 6. **Prometheus-compatible**: Metrics are exported in Prometheus format
//! 7. **Service Module Integration**: Implements the `ServiceModule` trait for seamless integration
//! 
//! ## Usage
//! 
//! ```rust
//! use ri::prelude::*;
//! 
//! fn example() -> RiResult<()> {
//!     // Create a Ri app builder
//!     let mut builder = RiAppBuilder::new();
//!     
//!     // Configure observability
//!     let observability_config = RiObservabilityConfig {
//!         tracing_enabled: true,
//!         metrics_enabled: true,
//!         tracing_sampling_rate: 0.5, // 50% sampling rate
//!         metrics_window_size_secs: 300,
//!         metrics_bucket_size_secs: 10,
//!     };
//!     
//!     // Add observability module to the app
//!     let observability_module = RiObservabilityModule::new()
//!         .with_config(observability_config);
//!     
//!     builder.add_module(Box::new(observability_module));
//!     
//!     // Build and run the app
//!     let mut app = builder.build()?;
//!     app.run()?;
//!     
//!     Ok(())
//! }
//! ```

mod metrics;
pub mod tracing;
pub mod propagation;
#[cfg(feature = "observability")]
pub mod prometheus;
#[cfg(feature = "system_info")]
mod metrics_collector;
pub mod grafana;

use std::sync::Arc;
use serde::{Serialize, Deserialize};

pub use tracing::{RiTracer, RiTraceId, RiSpanId, RiSpan, RiSpanKind, RiSpanStatus, RiTracingContext, RiSamplingStrategy};
pub use metrics::{RiMetricsRegistry, RiMetric, RiMetricConfig, RiMetricType, RiWindowStats, RiMetricSample};
pub use propagation::{RiTraceContext, RiBaggage, RiContextCarrier, W3CTracePropagator};
#[cfg(feature = "system_info")]
pub use metrics_collector::{RiSystemMetricsCollector, RiSystemMetrics, RiCPUMetrics, RiMemoryMetrics, RiDiskMetrics, RiNetworkMetrics};

use crate::core::{RiResult, RiServiceContext};


/// Main observability module for Ri.
/// 
/// This module provides distributed tracing and metrics collection capabilities, following modern
/// observability best practices. It implements the `ServiceModule` trait for seamless integration
/// with the Ri application lifecycle.
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct RiObservabilityModule {
    /// Distributed tracer instance
    tracer: Option<Arc<RiTracer>>,
    /// Metrics registry for collecting and aggregating metrics
    metrics_registry: Option<Arc<RiMetricsRegistry>>,
    /// Configuration for observability features
    config: RiObservabilityConfig,
}

/// Configuration for the observability module.
/// 
/// This struct defines the configuration options for tracing and metrics collection in Ri.
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiObservabilityConfig {
    /// Whether distributed tracing is enabled
    pub tracing_enabled: bool,
    /// Whether metrics collection is enabled
    pub metrics_enabled: bool,
    /// Sampling rate for distributed tracing (0.0 to 1.0)
    pub tracing_sampling_rate: f64,
    /// Sampling strategy for distributed tracing
    pub tracing_sampling_strategy: String,
    /// Window size for metrics aggregation in seconds
    pub metrics_window_size_secs: u64,
    /// Bucket size for metrics aggregation in seconds
    pub metrics_bucket_size_secs: u64,
}

impl Default for RiObservabilityConfig {
    /// Returns the default configuration for observability.
    /// 
    /// Default values:
    /// - tracing_enabled: true
    /// - metrics_enabled: true
    /// - tracing_sampling_rate: 0.1 (10% sampling)
    /// - tracing_sampling_strategy: "rate" (fixed rate sampling)
    /// - metrics_window_size_secs: 300 (5 minutes)
    /// - metrics_bucket_size_secs: 10 (10 seconds)
    fn default() -> Self {
        Self {
            tracing_enabled: true,
            metrics_enabled: true,
            tracing_sampling_rate: 0.1, // 10% sampling by default
            tracing_sampling_strategy: "rate".to_string(), // fixed rate sampling by default
            metrics_window_size_secs: 300, // 5 minutes
            metrics_bucket_size_secs: 10,  // 10 seconds
        }
    }
}

#[cfg(feature = "pyo3")]
/// Python methods for RiObservabilityConfig
#[pyo3::prelude::pymethods]
impl RiObservabilityConfig {
    #[new]
    fn py_new() -> Self {
        Self::default()
    }
    
    /// Set tracing enabled flag from Python
    fn set_tracing_enabled(&mut self, tracing_enabled: bool) {
        self.tracing_enabled = tracing_enabled;
    }
    
    /// Get tracing enabled flag from Python
    fn get_tracing_enabled(&self) -> bool {
        self.tracing_enabled
    }
    
    /// Set metrics enabled flag from Python
    fn set_metrics_enabled(&mut self, metrics_enabled: bool) {
        self.metrics_enabled = metrics_enabled;
    }
    
    /// Get metrics enabled flag from Python
    fn get_metrics_enabled(&self) -> bool {
        self.metrics_enabled
    }
    
    /// Set tracing sampling rate from Python
    fn set_tracing_sampling_rate(&mut self, tracing_sampling_rate: f64) -> pyo3::PyResult<()>
    {
        if tracing_sampling_rate < 0.0 || tracing_sampling_rate > 1.0 {
            return Err(pyo3::exceptions::PyValueError::new_err("Tracing sampling rate must be between 0.0 and 1.0"));
        }
        self.tracing_sampling_rate = tracing_sampling_rate;
        Ok(())
    }
    
    /// Get tracing sampling rate from Python
    fn get_tracing_sampling_rate(&self) -> f64 {
        self.tracing_sampling_rate
    }
    
    /// Set tracing sampling strategy from Python
    fn set_tracing_sampling_strategy(&mut self, tracing_sampling_strategy: String) {
        self.tracing_sampling_strategy = tracing_sampling_strategy;
    }
    
    /// Get tracing sampling strategy from Python
    fn get_tracing_sampling_strategy(&self) -> String {
        self.tracing_sampling_strategy.clone()
    }
    
    /// Set metrics window size in seconds from Python
    fn set_metrics_window_size_secs(&mut self, metrics_window_size_secs: u64) {
        self.metrics_window_size_secs = metrics_window_size_secs;
    }
    
    /// Get metrics window size in seconds from Python
    fn get_metrics_window_size_secs(&self) -> u64 {
        self.metrics_window_size_secs
    }
    
    /// Set metrics bucket size in seconds from Python
    fn set_metrics_bucket_size_secs(&mut self, metrics_bucket_size_secs: u64) {
        self.metrics_bucket_size_secs = metrics_bucket_size_secs;
    }
    
    /// Get metrics bucket size in seconds from Python
    fn get_metrics_bucket_size_secs(&self) -> u64 {
        self.metrics_bucket_size_secs
    }
}

impl Default for RiObservabilityModule {
    fn default() -> Self {
        Self::new()
    }
}

impl RiObservabilityModule {
    /// Creates a new observability module with default configuration.
    /// 
    /// # Returns
    /// 
    /// A new `RiObservabilityModule` instance with default configuration
    pub fn new() -> Self {
        Self {
            tracer: None,
            metrics_registry: None,
            config: RiObservabilityConfig::default(),
        }
    }
    
    /// Configures the observability module with custom settings.
    /// 
    /// # Parameters
    /// 
    /// - `config`: The custom configuration to apply
    /// 
    /// # Returns
    /// 
    /// The updated `RiObservabilityModule` instance
    pub fn with_config(mut self, config: RiObservabilityConfig) -> Self {
        self.config = config;
        self
    }
    
    /// Initializes tracing with the configured sampling strategy.
    /// 
    /// This method sets up the distributed tracer with the specified sampling strategy.
    fn init_tracing(&mut self) {
        if self.config.tracing_enabled {
            // Initialize tracer with the configured rate
            // Note: In a real implementation, we'd use the appropriate strategy
            tracing::init_tracer(self.config.tracing_sampling_rate);
        }
    }
    
    /// Initializes the metrics registry.
    /// 
    /// This method creates and configures the metrics registry for collecting and aggregating metrics.
    fn init_metrics(&mut self) {
        if self.config.metrics_enabled {
            let registry = Arc::new(RiMetricsRegistry::new());
            self.metrics_registry = Some(registry);
        }
    }
    
    /// Creates common service metrics.
    /// 
    /// This method registers standard service metrics including:
    /// - Request duration histogram
    /// - Request counter
    /// - Error counter
    /// - Active connections gauge
    /// - Service startup time
    /// - Module initialization time
    /// - Request queue length
    /// - Middleware execution time
    /// - Cache metrics (hits, misses, entries, memory usage)
    /// - Database query time
    /// 
    /// # Returns
    /// 
    /// A `RiResult<()>` indicating success or failure
    fn create_service_metrics(&self) -> RiResult<()> {
        if let Some(registry) = &self.metrics_registry {
            // Request duration histogram
            let request_duration_config = RiMetricConfig {
                metric_type: RiMetricType::Histogram,
                name: "dms_request_duration_seconds".to_string(),
                help: "Request duration in seconds".to_string(),
                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0], // seconds
                quantiles: vec![0.5, 0.9, 0.95, 0.99],
                max_age: std::time::Duration::from_secs(300),
                age_buckets: 5,
            };
            
            let request_duration_metric = Arc::new(RiMetric::new(request_duration_config));
            registry.register(request_duration_metric)?;
            
            // Request counter
            let request_counter_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_requests_total".to_string(),
                help: "Total number of requests".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let request_counter_metric = Arc::new(RiMetric::new(request_counter_config));
            registry.register(request_counter_metric)?;
            
            // Error counter
            let error_counter_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_errors_total".to_string(),
                help: "Total number of errors".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let error_counter_metric = Arc::new(RiMetric::new(error_counter_config));
            registry.register(error_counter_metric)?;
            
            // Active connections gauge
            let connections_gauge_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_active_connections".to_string(),
                help: "Number of active connections".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let connections_gauge_metric = Arc::new(RiMetric::new(connections_gauge_config));
            registry.register(connections_gauge_metric)?;
            
            // Service startup time gauge
            let startup_time_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_service_startup_time_seconds".to_string(),
                help: "Service startup time in seconds".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let startup_time_metric = Arc::new(RiMetric::new(startup_time_config));
            registry.register(startup_time_metric)?;
            
            // Module initialization time histogram
            let module_init_config = RiMetricConfig {
                metric_type: RiMetricType::Histogram,
                name: "dms_module_init_time_seconds".to_string(),
                help: "Module initialization time in seconds".to_string(),
                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0],
                quantiles: vec![0.5, 0.9, 0.95, 0.99],
                max_age: std::time::Duration::from_secs(300),
                age_buckets: 5,
            };
            
            let module_init_metric = Arc::new(RiMetric::new(module_init_config));
            registry.register(module_init_metric)?;
            
            // Request queue length gauge
            let queue_length_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_request_queue_length".to_string(),
                help: "Request queue length".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let queue_length_metric = Arc::new(RiMetric::new(queue_length_config));
            registry.register(queue_length_metric)?;
            
            // Middleware execution time histogram
            let middleware_time_config = RiMetricConfig {
                metric_type: RiMetricType::Histogram,
                name: "dms_middleware_duration_seconds".to_string(),
                help: "Middleware execution time in seconds".to_string(),
                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5],
                quantiles: vec![0.5, 0.9, 0.95, 0.99],
                max_age: std::time::Duration::from_secs(300),
                age_buckets: 5,
            };
            
            let middleware_time_metric = Arc::new(RiMetric::new(middleware_time_config));
            registry.register(middleware_time_metric)?;
            
            // Cache metrics
            // Cache hit counter
            let cache_hit_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_cache_hits_total".to_string(),
                help: "Total number of cache hits".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let cache_hit_metric = Arc::new(RiMetric::new(cache_hit_config));
            registry.register(cache_hit_metric)?;
            
            // Cache miss counter
            let cache_miss_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_cache_misses_total".to_string(),
                help: "Total number of cache misses".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let cache_miss_metric = Arc::new(RiMetric::new(cache_miss_config));
            registry.register(cache_miss_metric)?;
            
            // Cache entries gauge
            let cache_entries_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_cache_entries".to_string(),
                help: "Number of cache entries".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let cache_entries_metric = Arc::new(RiMetric::new(cache_entries_config));
            registry.register(cache_entries_metric)?;
            
            // Cache memory usage gauge
            let cache_memory_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_cache_memory_usage_bytes".to_string(),
                help: "Cache memory usage in bytes".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let cache_memory_metric = Arc::new(RiMetric::new(cache_memory_config));
            registry.register(cache_memory_metric)?;
            
            // Cache eviction counter
            let cache_eviction_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_cache_evictions_total".to_string(),
                help: "Total number of cache evictions".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let cache_eviction_metric = Arc::new(RiMetric::new(cache_eviction_config));
            registry.register(cache_eviction_metric)?;
            
            // Database metrics
            // Database query time histogram
            let db_query_config = RiMetricConfig {
                metric_type: RiMetricType::Histogram,
                name: "dms_db_query_duration_seconds".to_string(),
                help: "Database query execution time in seconds".to_string(),
                buckets: vec![0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0],
                quantiles: vec![0.5, 0.9, 0.95, 0.99],
                max_age: std::time::Duration::from_secs(300),
                age_buckets: 5,
            };
            
            let db_query_metric = Arc::new(RiMetric::new(db_query_config));
            registry.register(db_query_metric)?;
            
            // Database active connections gauge
            let db_active_connections_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_db_active_connections".to_string(),
                help: "Number of active database connections".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_active_connections_metric = Arc::new(RiMetric::new(db_active_connections_config));
            registry.register(db_active_connections_metric)?;
            
            // Database idle connections gauge
            let db_idle_connections_config = RiMetricConfig {
                metric_type: RiMetricType::Gauge,
                name: "dms_db_idle_connections".to_string(),
                help: "Number of idle database connections".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_idle_connections_metric = Arc::new(RiMetric::new(db_idle_connections_config));
            registry.register(db_idle_connections_metric)?;
            
            // Database connection timeouts counter
            let db_timeout_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_db_connection_timeouts_total".to_string(),
                help: "Total number of database connection timeouts".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_timeout_metric = Arc::new(RiMetric::new(db_timeout_config));
            registry.register(db_timeout_metric)?;
            
            // Database errors counter
            let db_errors_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_db_errors_total".to_string(),
                help: "Total number of database errors".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_errors_metric = Arc::new(RiMetric::new(db_errors_config));
            registry.register(db_errors_metric)?;
            
            // Database transactions counter
            let db_transactions_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_db_transactions_total".to_string(),
                help: "Total number of database transactions".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_transactions_metric = Arc::new(RiMetric::new(db_transactions_config));
            registry.register(db_transactions_metric)?;
            
            // Database transaction commits counter
            let db_commits_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_db_transaction_commits_total".to_string(),
                help: "Total number of database transaction commits".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_commits_metric = Arc::new(RiMetric::new(db_commits_config));
            registry.register(db_commits_metric)?;
            
            // Database transaction rollbacks counter
            let db_rollbacks_config = RiMetricConfig {
                metric_type: RiMetricType::Counter,
                name: "dms_db_transaction_rollbacks_total".to_string(),
                help: "Total number of database transaction rollbacks".to_string(),
                buckets: vec![],
                quantiles: vec![],
                max_age: std::time::Duration::from_secs(0),
                age_buckets: 0,
            };
            
            let db_rollbacks_metric = Arc::new(RiMetric::new(db_rollbacks_config));
            registry.register(db_rollbacks_metric)?;
        }
        
        Ok(())
    }
    
    /// Exports observability data.
    /// 
    /// This method collects and returns the current observability data, including metrics in Prometheus
    /// format and information about active traces and spans.
    /// 
    /// # Returns
    /// 
    /// A `RiObservabilityData` struct containing the exported observability data
    pub fn export_data(&self) -> RiObservabilityData {
        RiObservabilityData {
            metrics: {
                #[cfg(feature = "observability")]
                {
                    self.metrics_registry.as_ref().map(|r| r.export_prometheus()).unwrap_or_default()
                }
                #[cfg(not(feature = "observability"))]
                {
                    String::default()
                }
            },
            active_traces: self.tracer.as_ref().map(|_| tracing::tracer().map(|t| t.active_trace_count()).unwrap_or(0)).unwrap_or(0),
            active_spans: self.tracer.as_ref().map(|_| tracing::tracer().map(|t| t.active_span_count()).unwrap_or(0)).unwrap_or(0),
        }
    }
}

/// Exported observability data structure.
/// 
/// This struct represents the observability data that can be exported from the Ri system,
/// including metrics in Prometheus format and information about active traces and spans.
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiObservabilityData {
    /// Metrics data in Prometheus format
    pub metrics: String,
    /// Number of active traces
    pub active_traces: usize,
    /// Number of active spans
    pub active_spans: usize,
}

#[cfg(feature = "pyo3")]
/// Python methods for RiObservabilityData
#[pyo3::prelude::pymethods]
impl RiObservabilityData {
    /// Create new observability data from Python
    #[new]
    fn py_new(metrics: String, active_traces: usize, active_spans: usize) -> Self {
        Self {
            metrics,
            active_traces,
            active_spans,
        }
    }
    
    /// Get metrics data from Python
    #[pyo3(name = "get_metrics")]
    fn get_metrics_impl(&self) -> String {
        self.metrics.clone()
    }
    
    /// Get active traces count from Python
    #[pyo3(name = "get_active_traces")]
    fn get_active_traces_impl(&self) -> usize {
        self.active_traces
    }
    
    /// Get active spans count from Python
    #[pyo3(name = "get_active_spans")]
    fn get_active_spans_impl(&self) -> usize {
        self.active_spans
    }
}

#[cfg(feature = "pyo3")]
#[pyo3::prelude::pymethods]
impl RiObservabilityModule {
    fn get_metrics(&self) -> String {
        format!("ObservabilityModule with config: {:?}", self.config)
    }
}

#[async_trait::async_trait]
impl crate::core::RiModule for RiObservabilityModule {
    /// Returns the name of the observability module.
    /// 
    /// # Returns
    /// 
    /// The module name as a string
    fn name(&self) -> &str {
        "Ri.Observability"
    }
    
    /// Indicates whether the observability module is critical.
    /// 
    /// The observability module is non-critical, meaning that if it fails to initialize or operate,
    /// it should not break the entire application. This allows the core functionality to continue
    /// even if observability features are unavailable.
    /// 
    /// # Returns
    /// 
    /// `false` since observability is non-critical
    fn is_critical(&self) -> bool {
        false // Non-critical, should not break the app if observability fails
    }
    
    /// Initializes the observability module.
    /// 
    /// This method performs the following steps:
    /// 1. Loads configuration from the service context
    /// 2. Initializes tracing with the configured sampling rate
    /// 3. Initializes the metrics registry
    /// 4. Creates common service metrics
    /// 5. Registers lifecycle hooks for automatic metrics collection
    /// 6. Logs initialization completion
    /// 
    /// # Parameters
    /// 
    /// - `ctx`: The service context containing configuration and other services
    /// 
    /// # Returns
    /// 
    /// A `RiResult<()>` indicating success or failure
    async fn init(&mut self, ctx: &mut RiServiceContext) -> RiResult<()> {
        // Load configuration
        let binding = ctx.config();
        let cfg = binding.config();
        
        self.config = RiObservabilityConfig {
            tracing_enabled: cfg.get_bool("observability.tracing_enabled").unwrap_or(true),
            metrics_enabled: cfg.get_bool("observability.metrics_enabled").unwrap_or(true),
            tracing_sampling_rate: cfg.get_f32("observability.tracing_sampling_rate")
                .unwrap_or(0.1)
                .max(0.0)
                .min(1.0) as f64,
            tracing_sampling_strategy: cfg.get_str("observability.tracing_sampling_strategy")
                .unwrap_or("rate")
                .to_string(),
            metrics_window_size_secs: cfg.get_u64("observability.metrics_window_size_secs")
                .unwrap_or(300)
                .max(1),
            metrics_bucket_size_secs: cfg.get_u64("observability.metrics_bucket_size_secs")
                .unwrap_or(10)
                .max(1),
        };
        
        // Initialize components
        self.init_tracing();
        self.init_metrics();
        self.create_service_metrics()?;
        
        // Register lifecycle hooks
        let hooks: &mut crate::hooks::RiHookBus = ctx.hooks_mut();
        
        // Hook into request lifecycle for automatic metrics collection
        hooks.register(
            crate::hooks::RiHookKind::Startup,
            "dms.observability.lifecycle".to_string(),
            |_ctx, _event: &crate::hooks::RiHookEvent| {
                // Could add automatic span creation here
                Ok(())
            },
        );
        
        let logger = ctx.logger();
        logger.info("Ri.Observability", "Observability module initialized")?;
        
        Ok(())
    }
    
    /// Performs cleanup after the application has shut down.
    /// 
    /// This method exports the final observability data and logs information about active traces
    /// and spans at the time of shutdown.
    /// 
    /// # Parameters
    /// 
    /// - `ctx`: The service context containing the logger service
    /// 
    /// # Returns
    /// 
    /// A `RiResult<()>` indicating success or failure
    async fn after_shutdown(&mut self, ctx: &mut RiServiceContext) -> RiResult<()> {
        // Export final observability data
        let data = self.export_data();
        
        let logger = ctx.logger();
        logger.info("Ri.Observability", format!("Final observability data: {} active traces, {} active spans", 
            data.active_traces, data.active_spans))?;
        
        Ok(())
    }
}