scouter_tracing/exporter/
http.rs

1use std::collections::HashMap;
2
3use crate::error::TraceError;
4use crate::exporter::traits::SpanExporterBuilder;
5use crate::exporter::ExporterType;
6use crate::utils::{ExportConfig, OtelHttpConfig, OtelProtocol};
7use opentelemetry_otlp::ExportConfig as OtlpExportConfig;
8use opentelemetry_otlp::SpanExporter as OtlpSpanExporter;
9use opentelemetry_otlp::WithExportConfig;
10use opentelemetry_otlp::WithHttpConfig;
11use pyo3::prelude::*;
12use scouter_types::{CompressionType, PyHelperFuncs};
13use serde::Serialize;
14use std::time::Duration;
15
16#[derive(Debug, Clone, Serialize)]
17#[pyclass]
18pub struct HttpSpanExporter {
19    #[pyo3(get)]
20    pub sample_ratio: Option<f64>,
21
22    #[pyo3(get)]
23    pub batch_export: bool,
24
25    #[pyo3(get)]
26    endpoint: Option<String>,
27
28    #[pyo3(get)]
29    protocol: OtelProtocol,
30
31    #[pyo3(get)]
32    timeout: Option<u64>,
33
34    #[pyo3(get)]
35    headers: Option<HashMap<String, String>>,
36
37    #[pyo3(get)]
38    compression: Option<CompressionType>,
39}
40
41#[pymethods]
42impl HttpSpanExporter {
43    #[new]
44    #[pyo3(signature = (batch_export=true, export_config=None, http_config=None, sample_ratio=None))]
45    pub fn new(
46        batch_export: bool,
47        export_config: Option<&ExportConfig>,
48        http_config: Option<&OtelHttpConfig>,
49        sample_ratio: Option<f64>,
50    ) -> Result<Self, TraceError> {
51        let (endpoint, protocol, timeout) = if let Some(config) = export_config {
52            (
53                config.endpoint.clone(),
54                config.protocol.clone(),
55                config.timeout,
56            )
57        } else {
58            (None, OtelProtocol::default(), None)
59        };
60
61        let headers = http_config.and_then(|cfg| cfg.headers.clone());
62        let compression = if let Some(http_config) = http_config {
63            http_config.compression.clone()
64        } else {
65            None
66        };
67
68        Ok(Self {
69            batch_export,
70            sample_ratio,
71            endpoint,
72            protocol,
73            timeout,
74            headers,
75            compression,
76        })
77    }
78
79    pub fn __str__(&self) -> String {
80        PyHelperFuncs::__str__(self)
81    }
82}
83
84impl SpanExporterBuilder for HttpSpanExporter {
85    type Exporter = OtlpSpanExporter;
86
87    fn export_type(&self) -> ExporterType {
88        ExporterType::Http
89    }
90
91    fn sample_ratio(&self) -> Option<f64> {
92        self.sample_ratio
93    }
94
95    fn batch_export(&self) -> bool {
96        self.batch_export
97    }
98
99    fn build_exporter(&self) -> Result<Self::Exporter, TraceError> {
100        // Reconstruct the OtlpExportConfig each time
101        let timeout = self.timeout.map(Duration::from_secs);
102        let export_config = OtlpExportConfig {
103            endpoint: self.endpoint.clone(),
104            protocol: self.protocol.to_otel_protocol(),
105            timeout,
106        };
107
108        let mut exporter = opentelemetry_otlp::SpanExporter::builder()
109            .with_http()
110            .with_export_config(export_config);
111
112        if let Some(headers) = &self.headers {
113            exporter = exporter.with_headers(headers.clone());
114        }
115
116        if let Some(compression) = &self.compression {
117            exporter = exporter.with_compression(compression.to_otel_compression()?);
118        }
119
120        Ok(exporter.build()?)
121    }
122}