apollo-opentelemetry 0.8.0

OpenTelemetry configuration types for Apollo platform
Documentation
//! Grafana Cloud OTLP exporter builders.
//!
//! Grafana Cloud accepts OTLP data with Basic authentication using instance ID and API key.
//!
//! See [Grafana Cloud OTLP documentation](https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/)
//! for details on endpoints and authentication.

use crate::InitError;
use crate::config::exporters::GrafanaCloudHttpExporterConfig;
use crate::error::ExporterKind;

/// Build an HTTP span exporter for Grafana Cloud.
///
/// See [Grafana Cloud OTLP endpoint](https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/#before-you-begin).
pub(crate) fn build_http_span_exporter(
    config: &GrafanaCloudHttpExporterConfig,
) -> Result<opentelemetry_otlp::SpanExporter, InitError> {
    use opentelemetry_otlp::{SpanExporter, WithExportConfig, WithHttpConfig};

    let mut headers = std::collections::HashMap::new();
    headers.insert("Authorization".to_string(), config.auth_header());

    SpanExporter::builder()
        .with_http()
        .with_endpoint(config.endpoint.as_str())
        .with_headers(headers)
        .build()
        .map_err(|e| InitError::Exporter {
            exporter: ExporterKind::GrafanaCloudHttp,
            reason: e.to_string(),
        })
}

/// Build an HTTP log exporter for Grafana Cloud.
///
/// See [Grafana Cloud OTLP endpoint](https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/#before-you-begin).
pub(crate) fn build_http_log_exporter(
    config: &GrafanaCloudHttpExporterConfig,
) -> Result<opentelemetry_otlp::LogExporter, InitError> {
    use opentelemetry_otlp::{LogExporter, WithExportConfig, WithHttpConfig};

    let endpoint = format!("{}/v1/logs", config.endpoint);

    let mut headers = std::collections::HashMap::new();
    headers.insert("Authorization".to_string(), config.auth_header());

    LogExporter::builder()
        .with_http()
        .with_endpoint(endpoint)
        .with_headers(headers)
        .build()
        .map_err(|e| InitError::Exporter {
            exporter: ExporterKind::GrafanaCloudHttp,
            reason: e.to_string(),
        })
}

/// Build an HTTP metric exporter for Grafana Cloud.
///
/// See [Grafana Cloud OTLP endpoint](https://grafana.com/docs/grafana-cloud/send-data/otlp/send-data-otlp/#before-you-begin).
pub(crate) fn build_http_metric_exporter(
    config: &GrafanaCloudHttpExporterConfig,
) -> Result<opentelemetry_otlp::MetricExporter, InitError> {
    use opentelemetry_otlp::{MetricExporter, WithExportConfig, WithHttpConfig};

    let endpoint = format!("{}/v1/metrics", config.endpoint);

    let mut headers = std::collections::HashMap::new();
    headers.insert("Authorization".to_string(), config.auth_header());

    MetricExporter::builder()
        .with_http()
        .with_endpoint(endpoint)
        .with_headers(headers)
        .build()
        .map_err(|e| InitError::Exporter {
            exporter: ExporterKind::GrafanaCloudHttp,
            reason: e.to_string(),
        })
}

#[cfg(test)]
mod tests {
    use apollo_configuration::parse_yaml;

    use super::*;
    use crate::config::OpenTelemetryConfig;
    use crate::config::SpanExporter;
    use crate::config::traces::SpanProcessor;

    fn get_grafana_cloud_config(config: &OpenTelemetryConfig) -> &GrafanaCloudHttpExporterConfig {
        match &config.tracer_provider.processors[0] {
            SpanProcessor::Batch(batch) => match &batch.exporter {
                SpanExporter::GrafanaCloud(gc) => gc,
                _ => panic!("Expected GrafanaCloud exporter"),
            },
            _ => panic!("Expected Batch processor"),
        }
    }

    #[test]
    fn build_http_span_exporter_from_config() {
        let config: OpenTelemetryConfig = parse_yaml(
            indoc::indoc! {"
                tracer_provider:
                  processors:
                    - batch:
                        exporter:
                          grafana_cloud:
                            instance_id: '123456'
                            api_key: glc_test_key
                            endpoint: https://otlp-gateway-prod-us-central-0.grafana.net/otlp
            "},
            &Default::default(),
        )
        .unwrap();

        let gc = get_grafana_cloud_config(&config);
        let result = build_http_span_exporter(gc);
        assert!(result.is_ok());
    }

    #[test]
    fn build_http_log_exporter_from_config() {
        let config: OpenTelemetryConfig = parse_yaml(
            indoc::indoc! {"
                tracer_provider:
                  processors:
                    - batch:
                        exporter:
                          grafana_cloud:
                            instance_id: '123456'
                            api_key: glc_test_key
                            endpoint: https://otlp-gateway-prod-us-central-0.grafana.net/otlp
            "},
            &Default::default(),
        )
        .unwrap();

        let gc = get_grafana_cloud_config(&config);
        let result = build_http_log_exporter(gc);
        assert!(result.is_ok());
    }

    #[test]
    fn build_http_metric_exporter_from_config() {
        let config: OpenTelemetryConfig = parse_yaml(
            indoc::indoc! {"
                tracer_provider:
                  processors:
                    - batch:
                        exporter:
                          grafana_cloud:
                            instance_id: '123456'
                            api_key: glc_test_key
                            endpoint: https://otlp-gateway-prod-us-central-0.grafana.net/otlp
            "},
            &Default::default(),
        )
        .unwrap();

        let gc = get_grafana_cloud_config(&config);
        let result = build_http_metric_exporter(gc);
        assert!(result.is_ok());
    }
}