Skip to main content

mockforge_observability/
lib.rs

1//! MockForge Observability
2//!
3//! Provides comprehensive observability features including:
4//! - Structured logging with JSON support
5//! - Prometheus metrics export
6//! - OpenTelemetry distributed tracing
7//! - Request/response recording (flight recorder)
8//! - Scenario control and chaos engineering
9//! - System metrics collection (CPU, memory, threads)
10//!
11//! # Example
12//!
13//! ```rust
14//! use mockforge_observability::prometheus::MetricsRegistry;
15//!
16//! let registry = MetricsRegistry::new();
17//! registry.record_http_request("GET", 200, 0.045);
18//! ```
19
20#[cfg(feature = "log-shipper")]
21pub mod log_shipper;
22pub mod logging;
23pub mod prometheus;
24#[cfg(feature = "sentry")]
25pub mod sentry_init;
26pub mod system_metrics;
27pub mod tracing_integration;
28
29// Re-export commonly used items
30pub use logging::{init_logging, init_logging_with_otel, LoggingConfig};
31pub use prometheus::{get_global_registry, MetricsRegistry};
32#[cfg(feature = "sentry")]
33pub use sentry_init::init_sentry;
34pub use system_metrics::{start_system_metrics_collector, SystemMetricsConfig};
35pub use tracing_integration::{init_with_otel, shutdown_otel, OtelTracingConfig};
36
37/// Protocol types for metrics tracking
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub enum Protocol {
40    Http,
41    Grpc,
42    WebSocket,
43    GraphQL,
44}
45
46impl Protocol {
47    pub fn as_str(&self) -> &'static str {
48        match self {
49            Protocol::Http => "http",
50            Protocol::Grpc => "grpc",
51            Protocol::WebSocket => "websocket",
52            Protocol::GraphQL => "graphql",
53        }
54    }
55}
56
57impl std::fmt::Display for Protocol {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(f, "{}", self.as_str())
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use std::collections::HashSet;
67
68    #[test]
69    fn test_protocol_display() {
70        assert_eq!(Protocol::Http.to_string(), "http");
71        assert_eq!(Protocol::Grpc.to_string(), "grpc");
72        assert_eq!(Protocol::WebSocket.to_string(), "websocket");
73        assert_eq!(Protocol::GraphQL.to_string(), "graphql");
74    }
75
76    #[test]
77    fn test_protocol_as_str() {
78        assert_eq!(Protocol::Http.as_str(), "http");
79        assert_eq!(Protocol::Grpc.as_str(), "grpc");
80        assert_eq!(Protocol::WebSocket.as_str(), "websocket");
81        assert_eq!(Protocol::GraphQL.as_str(), "graphql");
82    }
83
84    #[test]
85    fn test_protocol_debug() {
86        assert_eq!(format!("{:?}", Protocol::Http), "Http");
87        assert_eq!(format!("{:?}", Protocol::Grpc), "Grpc");
88        assert_eq!(format!("{:?}", Protocol::WebSocket), "WebSocket");
89        assert_eq!(format!("{:?}", Protocol::GraphQL), "GraphQL");
90    }
91
92    #[test]
93    fn test_protocol_clone() {
94        let proto = Protocol::Http;
95        let cloned = Clone::clone(&proto);
96        assert_eq!(proto, cloned);
97    }
98
99    #[test]
100    fn test_protocol_copy() {
101        let proto = Protocol::Grpc;
102        let copied = proto;
103        assert_eq!(Protocol::Grpc, copied);
104        assert_eq!(proto, Protocol::Grpc); // proto still accessible
105    }
106
107    #[test]
108    fn test_protocol_eq() {
109        assert_eq!(Protocol::Http, Protocol::Http);
110        assert_eq!(Protocol::Grpc, Protocol::Grpc);
111        assert_ne!(Protocol::Http, Protocol::Grpc);
112        assert_ne!(Protocol::WebSocket, Protocol::GraphQL);
113    }
114
115    #[test]
116    fn test_protocol_hash() {
117        let mut set = HashSet::new();
118        set.insert(Protocol::Http);
119        set.insert(Protocol::Grpc);
120        set.insert(Protocol::WebSocket);
121        set.insert(Protocol::GraphQL);
122
123        assert_eq!(set.len(), 4);
124        assert!(set.contains(&Protocol::Http));
125        assert!(set.contains(&Protocol::Grpc));
126        assert!(set.contains(&Protocol::WebSocket));
127        assert!(set.contains(&Protocol::GraphQL));
128
129        // Duplicate insertion shouldn't increase size
130        set.insert(Protocol::Http);
131        assert_eq!(set.len(), 4);
132    }
133
134    #[test]
135    fn test_protocol_all_variants() {
136        let protocols = [
137            Protocol::Http,
138            Protocol::Grpc,
139            Protocol::WebSocket,
140            Protocol::GraphQL,
141        ];
142
143        for proto in protocols {
144            let str_repr = proto.as_str();
145            assert!(!str_repr.is_empty());
146            assert_eq!(proto.to_string(), str_repr);
147        }
148    }
149}