rustfs_obs/global.rs
1// Copyright 2024 RustFS Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::logger::InitLogStatus;
16use crate::telemetry::{OtelGuard, init_telemetry};
17use crate::{AppConfig, Logger, get_global_logger, init_global_logger};
18use std::sync::{Arc, Mutex};
19use tokio::sync::{OnceCell, SetError};
20use tracing::{error, info};
21
22/// Global guard for OpenTelemetry tracing
23static GLOBAL_GUARD: OnceCell<Arc<Mutex<OtelGuard>>> = OnceCell::const_new();
24
25/// Error type for global guard operations
26#[derive(Debug, thiserror::Error)]
27pub enum GlobalError {
28 #[error("Failed to set global guard: {0}")]
29 SetError(#[from] SetError<Arc<Mutex<OtelGuard>>>),
30 #[error("Global guard not initialized")]
31 NotInitialized,
32 #[error("Global system metrics err: {0}")]
33 MetricsError(String),
34 #[error("Failed to get current PID: {0}")]
35 PidError(String),
36 #[error("Process with PID {0} not found")]
37 ProcessNotFound(u32),
38 #[error("Failed to get physical core count")]
39 CoreCountError,
40 #[error("GPU initialization failed: {0}")]
41 GpuInitError(String),
42 #[error("GPU device not found: {0}")]
43 GpuDeviceError(String),
44 #[error("Failed to send log: {0}")]
45 SendFailed(&'static str),
46 #[error("Operation timed out: {0}")]
47 Timeout(&'static str),
48}
49
50/// Initialize the observability module
51///
52/// # Parameters
53/// - `config`: Configuration information
54///
55/// # Returns
56/// A tuple containing the logger and the telemetry guard
57///
58/// # Example
59/// ```no_run
60/// use rustfs_obs::init_obs;
61///
62/// # #[tokio::main]
63/// # async fn main() {
64/// let (logger, guard) = init_obs(None).await;
65/// # }
66/// ```
67pub async fn init_obs(endpoint: Option<String>) -> (Arc<tokio::sync::Mutex<Logger>>, OtelGuard) {
68 // Load the configuration file
69 let config = AppConfig::new_with_endpoint(endpoint);
70
71 let guard = init_telemetry(&config.observability);
72
73 let logger = init_global_logger(&config).await;
74 let obs_config = config.observability.clone();
75 tokio::spawn(async move {
76 let result = InitLogStatus::init_start_log(&obs_config).await;
77 match result {
78 Ok(_) => {
79 info!("Logger initialized successfully");
80 }
81 Err(e) => {
82 error!("Failed to initialize logger: {}", e);
83 }
84 }
85 });
86
87 (logger, guard)
88}
89
90/// Get the global logger instance
91/// This function returns a reference to the global logger instance.
92///
93/// # Returns
94/// A reference to the global logger instance
95///
96/// # Example
97/// ```no_run
98/// use rustfs_obs::get_logger;
99///
100/// let logger = get_logger();
101/// ```
102pub fn get_logger() -> &'static Arc<tokio::sync::Mutex<Logger>> {
103 get_global_logger()
104}
105
106/// Set the global guard for OpenTelemetry
107///
108/// # Arguments
109/// * `guard` - The OtelGuard instance to set globally
110///
111/// # Returns
112/// * `Ok(())` if successful
113/// * `Err(GuardError)` if setting fails
114///
115/// # Example
116/// ```rust
117/// use rustfs_obs::{ init_obs, set_global_guard};
118///
119/// async fn init() -> Result<(), Box<dyn std::error::Error>> {
120/// let (_, guard) = init_obs(None).await;
121/// set_global_guard(guard)?;
122/// Ok(())
123/// }
124/// ```
125pub fn set_global_guard(guard: OtelGuard) -> Result<(), GlobalError> {
126 info!("Initializing global OpenTelemetry guard");
127 GLOBAL_GUARD.set(Arc::new(Mutex::new(guard))).map_err(GlobalError::SetError)
128}
129
130/// Get the global guard for OpenTelemetry
131///
132/// # Returns
133/// * `Ok(Arc<Mutex<OtelGuard>>)` if guard exists
134/// * `Err(GuardError)` if guard not initialized
135///
136/// # Example
137/// ```rust
138/// use rustfs_obs::get_global_guard;
139///
140/// async fn trace_operation() -> Result<(), Box<dyn std::error::Error>> {
141/// let guard = get_global_guard()?;
142/// let _lock = guard.lock().unwrap();
143/// // Perform traced operation
144/// Ok(())
145/// }
146/// ```
147pub fn get_global_guard() -> Result<Arc<Mutex<OtelGuard>>, GlobalError> {
148 GLOBAL_GUARD.get().cloned().ok_or(GlobalError::NotInitialized)
149}
150
151/// Try to get the global guard for OpenTelemetry
152///
153/// # Returns
154/// * `Some(Arc<Mutex<OtelGuard>>)` if guard exists
155/// * `None` if guard not initialized
156pub fn try_get_global_guard() -> Option<Arc<Mutex<OtelGuard>>> {
157 GLOBAL_GUARD.get().cloned()
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 #[tokio::test]
164 async fn test_get_uninitialized_guard() {
165 let result = get_global_guard();
166 assert!(matches!(result, Err(GlobalError::NotInitialized)));
167 }
168}