metry 0.1.1

All-in-one telemetry framework, based on tracing crate.
Documentation
use tracing::level_filters::LevelFilter;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

use crate::{layers::TelemetryLayerBuilder, logs, metrics, trace};

use super::Level;

/// Create default telemetry pipeline.
pub fn new() -> TelemetryPipeline {
    TelemetryPipeline::default()
}

/// General builder for telemetry.
#[derive(Debug, Default)]
pub struct TelemetryPipeline {
    level: Option<LevelFilter>,
    /// By default, if this option is not used, no logs are emitted.
    logs_layer: Option<logs::LayerBuilder>,
    /// By default, if this option is not used, no metrics are emitted.
    metrics_layer: Option<metrics::LayerBuilder>,
    /// By default, if this option is not used, no traces are emitted.
    trace_layer: Option<trace::LayerBuilder>,
}

impl TelemetryPipeline {
    /// Associates a [logs::LayerBuilder] with a [TelemetryPipeline].
    ///
    /// This [logs::LayerBuilder] represents the entity producing logs.
    pub fn with_logs(mut self, config: logs::LayerBuilder) -> Self {
        self.logs_layer = Some(config);
        self
    }

    /// Associates a [logs::LayerBuilder::Stdout]
    /// and [logs::LogOptions::default()] with a [TelemetryPipeline].
    ///
    /// This [logs::LayerBuilder] represents the entity writing logs to stdout.
    pub fn with_stdout_logs(self) -> Self {
        self.with_logs(logs::LayerBuilder::Stdout(logs::LogOptions::default()))
    }

    /// Associates a [metrics::LayerBuilder] with a [TelemetryPipeline].
    ///
    /// This [metrics::LayerBuilder] represents the entity producing metrics.
    pub fn with_metrics(mut self, config: metrics::LayerBuilder) -> Self {
        self.metrics_layer = Some(config);
        self
    }

    /// Associates a [metrics::LayerBuilder::CloudWatch]
    /// and [metrics::CloudWatchMetricsOptions::default()] with a [TelemetryPipeline].
    ///
    /// This [metrics::LayerBuilder] represents the entity producing metrics.
    pub fn with_aws_metrics(self) -> Self {
        self.with_metrics(metrics::LayerBuilder::CloudWatch(
            metrics::CloudWatchMetricsOptions::default(),
        ))
    }

    /// Associates a [trace::LayerBuilder] with a [TelemetryPipeline].
    ///
    /// This [trace::LayerBuilder] represents the entity producing traces.
    pub fn with_traces(mut self, config: trace::LayerBuilder) -> Self {
        self.trace_layer = Some(config);
        self
    }

    /// Associates a [trace::LayerBuilder::Xray]
    /// and [trace::TraceOptions::default()] with a [TelemetryPipeline].
    ///
    /// This [trace::LayerBuilder] represents the entity producing traces.
    pub fn with_aws_traces(self) -> Self {
        self.with_traces(trace::LayerBuilder::Xray(trace::TraceOptions::default()))
    }

    /// Set level to filter out spans and events.
    pub fn with_level(mut self, level: Level) -> Self {
        self.level = Some(level.into());
        self
    }

    /// Initialize all configured telemetry subscribers
    pub async fn init(self) {
        let logs_layer = match self.logs_layer {
            Some(log_config) => log_config
                .layer()
                .await
                .inspect_err(|e| eprintln!("{e}"))
                .ok(),
            None => None,
        };
        let metrics_layer = match self.metrics_layer {
            Some(metrics_config) => metrics_config
                .layer()
                .await
                .inspect_err(|e| eprintln!("{e}"))
                .ok(),
            None => None,
        };
        let trace_layer = match self.trace_layer {
            Some(trace_config) => trace_config
                .layer()
                .await
                .inspect_err(|e| eprintln!("{e}"))
                .ok(),
            None => None,
        };
        let log_level = self.level.unwrap_or(LevelFilter::INFO).to_string();

        let tracing_registry = tracing_subscriber::registry()
            .with(logs_layer)
            .with(metrics_layer)
            .with(trace_layer)
            .with(EnvFilter::new(log_level))
            .try_init();
        if let Err(e) = tracing_registry {
            eprintln!("Failed initializing telemetry. {e:#?}");
        }
    }
}