scirs2_core/observability/audit/utils.rs
1//! Utility functions for the audit logging system
2
3/// Get thread ID as a numeric value
4#[must_use]
5#[allow(dead_code)]
6pub fn get_thread_id() -> u64 {
7 use std::thread;
8 // This is a simplified implementation
9 // In production, you'd use proper thread ID detection
10 format!("{:?}", thread::current().id())
11 .chars()
12 .filter_map(|c| c.to_digit(10))
13 .map(|d| d as u64)
14 .fold(0, |acc, d| acc * 10 + d)
15}
16
17/// Get hostname from environment variables
18#[must_use]
19#[allow(dead_code)]
20pub fn get_hostname() -> String {
21 std::env::var("HOSTNAME")
22 .or_else(|_| std::env::var("COMPUTERNAME"))
23 .unwrap_or_else(|_| "unknown".to_string())
24}
25
26/// Get local IP address
27#[must_use]
28#[allow(dead_code)]
29pub fn get_local_ip() -> Option<String> {
30 // Try to get the actual local IP address
31 #[cfg(feature = "sysinfo")]
32 {
33 use std::net::UdpSocket;
34
35 // Determine the local IP via a UDP "connect": for a datagram socket
36 // this only asks the OS routing table which local interface/address
37 // would be used to reach the given destination -- no handshake and no
38 // packet is ever actually sent on the wire, so it resolves instantly
39 // regardless of network reachability.
40 //
41 // NOTE: this previously used `TcpStream::connect("8.8.8.8:80")`,
42 // which performs a real SYN and blocks for the platform's full TCP
43 // connect timeout (~75s observed on macOS) whenever the destination
44 // is unreachable -- e.g. in firewalled/air-gapped/network-restricted
45 // deployments. Because `include_system_context` defaults to `true`,
46 // that made every default-configured audit-logged event pay a ~75s
47 // stall in exactly the kind of environment audit logging is normally
48 // deployed into. The UDP-based lookup below cannot block on the
49 // network at all.
50 if let Ok(socket) = UdpSocket::bind("0.0.0.0:0") {
51 if socket.connect("8.8.8.8:80").is_ok() {
52 if let Ok(local_addr) = socket.local_addr() {
53 return Some(local_addr.ip().to_string());
54 }
55 }
56 }
57
58 // Fallback: try to get from network interfaces
59 // This would require additional network interface detection
60 // For now, return a reasonable default
61 Some("127.0.0.1".to_string())
62 }
63
64 #[cfg(not(feature = "sysinfo"))]
65 {
66 // Simple fallback without network detection
67 use std::env;
68
69 // Check for common environment variables that might contain IP
70 if let Ok(ip) = env::var("HOST_IP") {
71 return Some(ip);
72 }
73
74 if let Ok(ip) = env::var("LOCAL_IP") {
75 return Some(ip);
76 }
77
78 // Default fallback
79 Some("127.0.0.1".to_string())
80 }
81}
82
83/// Get simplified stack trace
84#[must_use]
85#[allow(dead_code)]
86pub fn get_stack_trace() -> String {
87 // Simplified stack trace implementation for compatibility
88 let mut result = String::new();
89 result.push_str("Stack trace (simplified):\n");
90
91 // Get current thread and function info
92 if let Some(name) = std::thread::current().name() {
93 result.push_str(&format!(" Thread: {name}\n"));
94 } else {
95 result.push_str(" Thread: <unnamed>\n");
96 }
97
98 // Add caller information (simplified)
99 result.push_str(&format!(
100 " Location: {}:{}:{}\n",
101 file!(),
102 line!(),
103 column!()
104 ));
105
106 result
107}