openserve 2.0.3

A modern, high-performance, AI-enhanced file server built in Rust
Documentation
//! Telemetry Module
//! 
//! This module is responsible for configuring and initializing
//! all telemetry-related components, including logging, metrics,
//! and distributed tracing. It ensures that the application is
//! observable and provides insights into its performance and behavior.

use anyhow::Result;

use tracing_subscriber::{
    layer::SubscriberExt,
    util::SubscriberInitExt,
    EnvFilter,
    Registry,
};
use tracing_appender::rolling::{RollingFileAppender, Rotation};

use crate::config::TelemetryConfig;

/// Initializes the telemetry system.
///
/// This function sets up logging, and optionally metrics and tracing, based on the
/// provided `TelemetryConfig`. It supports both console and file-based
/// logging in either plain text or JSON format.
///
/// # Arguments
///
/// * `config` - A reference to the `TelemetryConfig` containing telemetry settings.
///
/// # Returns
///
/// A `Result` indicating whether the initialization was successful.
pub fn init(config: &TelemetryConfig) -> Result<()> {
    let file_appender = RollingFileAppender::new(Rotation::DAILY, "logs", "openserve.log");

    let env_filter = EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| EnvFilter::new(&config.log_level));

    let subscriber = Registry::default().with(env_filter);

    match config.log_format.as_str() {
        "json" => {
            let fmt_layer = tracing_subscriber::fmt::layer()
                .json()
                .with_writer(std::io::stdout);
            let file_layer = tracing_subscriber::fmt::layer()
                .json()
                .with_writer(file_appender);
            
            subscriber
                .with(fmt_layer)
                .with(file_layer)
                .init();
        }
        _ => {
            let fmt_layer = tracing_subscriber::fmt::layer()
                .with_writer(std::io::stdout);
            let file_layer = tracing_subscriber::fmt::layer()
                .with_writer(file_appender);

            subscriber
                .with(fmt_layer)
                .with(file_layer)
                .init();
        }
    }

    if config.metrics_enabled {
        init_metrics()?;
    }

    Ok(())
}

/// Initializes the Prometheus metrics system.
///
/// This function registers standard HTTP metrics, such as request counts
/// and latency histograms. These metrics can be exposed via a `/metrics`
/// endpoint for scraping by a Prometheus server.
///
/// # Returns
///
/// A `Result` indicating success or failure.
fn init_metrics() -> Result<()> {
    #[cfg(feature = "metrics")]
    {
        use prometheus::{Counter, Histogram, register_counter, register_histogram};
        use once_cell::sync::Lazy;

        // A counter for the total number of HTTP requests.
        static HTTP_REQUESTS_TOTAL: Lazy<Counter> = Lazy::new(|| {
            register_counter!("http_requests_total", "Total number of HTTP requests")
                .expect("Failed to register counter")
        });

        // A histogram to measure the duration of HTTP requests.
        static HTTP_REQUEST_DURATION: Lazy<Histogram> = Lazy::new(|| {
            register_histogram!("http_request_duration_seconds", "HTTP request duration")
                .expect("Failed to register histogram")
        });
    }

    Ok(())
}

/// Initializes the distributed tracing system with OpenTelemetry.
///
/// This function sets up an OTLP (OpenTelemetry Protocol) exporter to send
/// trace data to a specified collector endpoint. This is essential for
/// monitoring and debugging in a microservices architecture.
///
/// # Arguments
///
/// * `config` - A reference to the `TelemetryConfig` which contains the OTLP endpoint.
///
/// # Returns
///
/// A `Result` indicating success or failure.
#[allow(dead_code)]
fn init_tracing(_config: &TelemetryConfig) -> Result<()> {
    // OpenTelemetry tracing is disabled for now due to version conflicts
    // TODO: Re-enable when dependencies are compatible
    Ok(())
}