opentelemetry_otlp/
span.rs

1//! # OTLP - Span Exporter
2//!
3//! Defines a [SpanExporter] to send trace data via the OpenTelemetry Protocol (OTLP)
4
5use std::fmt::Debug;
6
7use opentelemetry_sdk::error::OTelSdkResult;
8use opentelemetry_sdk::trace::SpanData;
9
10use crate::ExporterBuildError;
11#[cfg(feature = "grpc-tonic")]
12use crate::{
13    exporter::tonic::{HasTonicConfig, TonicExporterBuilder},
14    TonicExporterBuilderSet,
15};
16
17#[cfg(any(feature = "http-proto", feature = "http-json"))]
18use crate::{
19    exporter::http::{HasHttpConfig, HttpExporterBuilder},
20    HttpExporterBuilderSet,
21};
22
23use crate::{exporter::HasExportConfig, NoExporterBuilderSet};
24
25/// Target to which the exporter is going to send spans, defaults to https://localhost:4317/v1/traces.
26/// Learn about the relationship between this constant and default/metrics/logs at
27/// <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#endpoint-urls-for-otlphttp>
28pub const OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: &str = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
29/// Max waiting time for the backend to process each spans batch, defaults to 10s.
30pub const OTEL_EXPORTER_OTLP_TRACES_TIMEOUT: &str = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT";
31/// Compression algorithm to use, defaults to none.
32pub const OTEL_EXPORTER_OTLP_TRACES_COMPRESSION: &str = "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION";
33/// Key-value pairs to be used as headers associated with gRPC or HTTP requests
34/// for sending spans.
35/// Example: `k1=v1,k2=v2`
36/// Note: this is only supported for HTTP.
37pub const OTEL_EXPORTER_OTLP_TRACES_HEADERS: &str = "OTEL_EXPORTER_OTLP_TRACES_HEADERS";
38
39/// OTLP span exporter builder
40#[derive(Debug, Default, Clone)]
41pub struct SpanExporterBuilder<C> {
42    client: C,
43}
44
45impl SpanExporterBuilder<NoExporterBuilderSet> {
46    /// Create a new [SpanExporterBuilder] with default settings.
47    pub fn new() -> Self {
48        SpanExporterBuilder::default()
49    }
50
51    /// With the gRPC Tonic transport.
52    #[cfg(feature = "grpc-tonic")]
53    pub fn with_tonic(self) -> SpanExporterBuilder<TonicExporterBuilderSet> {
54        SpanExporterBuilder {
55            client: TonicExporterBuilderSet(TonicExporterBuilder::default()),
56        }
57    }
58
59    /// With the HTTP transport.
60    #[cfg(any(feature = "http-proto", feature = "http-json"))]
61    pub fn with_http(self) -> SpanExporterBuilder<HttpExporterBuilderSet> {
62        SpanExporterBuilder {
63            client: HttpExporterBuilderSet(HttpExporterBuilder::default()),
64        }
65    }
66}
67
68#[cfg(feature = "grpc-tonic")]
69impl SpanExporterBuilder<TonicExporterBuilderSet> {
70    /// Build the [SpanExporter] with the gRPC Tonic transport.
71    pub fn build(self) -> Result<SpanExporter, ExporterBuildError> {
72        let span_exporter = self.client.0.build_span_exporter()?;
73        opentelemetry::otel_debug!(name: "SpanExporterBuilt");
74        Ok(span_exporter)
75    }
76}
77
78#[cfg(any(feature = "http-proto", feature = "http-json"))]
79impl SpanExporterBuilder<HttpExporterBuilderSet> {
80    /// Build the [SpanExporter] with the HTTP transport.
81    pub fn build(self) -> Result<SpanExporter, ExporterBuildError> {
82        let span_exporter = self.client.0.build_span_exporter()?;
83        Ok(span_exporter)
84    }
85}
86
87#[cfg(feature = "grpc-tonic")]
88impl HasExportConfig for SpanExporterBuilder<TonicExporterBuilderSet> {
89    fn export_config(&mut self) -> &mut crate::ExportConfig {
90        &mut self.client.0.exporter_config
91    }
92}
93
94#[cfg(any(feature = "http-proto", feature = "http-json"))]
95impl HasExportConfig for SpanExporterBuilder<HttpExporterBuilderSet> {
96    fn export_config(&mut self) -> &mut crate::ExportConfig {
97        &mut self.client.0.exporter_config
98    }
99}
100
101#[cfg(feature = "grpc-tonic")]
102impl HasTonicConfig for SpanExporterBuilder<TonicExporterBuilderSet> {
103    fn tonic_config(&mut self) -> &mut crate::TonicConfig {
104        &mut self.client.0.tonic_config
105    }
106}
107
108#[cfg(any(feature = "http-proto", feature = "http-json"))]
109impl HasHttpConfig for SpanExporterBuilder<HttpExporterBuilderSet> {
110    fn http_client_config(&mut self) -> &mut crate::exporter::http::HttpConfig {
111        &mut self.client.0.http_config
112    }
113}
114
115/// OTLP exporter that sends tracing data
116#[derive(Debug)]
117pub struct SpanExporter {
118    client: SupportedTransportClient,
119}
120
121#[derive(Debug)]
122enum SupportedTransportClient {
123    #[cfg(feature = "grpc-tonic")]
124    Tonic(crate::exporter::tonic::trace::TonicTracesClient),
125    #[cfg(any(feature = "http-proto", feature = "http-json"))]
126    Http(crate::exporter::http::OtlpHttpClient),
127}
128
129impl SpanExporter {
130    /// Obtain a builder to configure a [SpanExporter].
131    pub fn builder() -> SpanExporterBuilder<NoExporterBuilderSet> {
132        SpanExporterBuilder::default()
133    }
134
135    #[cfg(any(feature = "http-proto", feature = "http-json"))]
136    pub(crate) fn from_http(client: crate::exporter::http::OtlpHttpClient) -> Self {
137        SpanExporter {
138            client: SupportedTransportClient::Http(client),
139        }
140    }
141
142    #[cfg(feature = "grpc-tonic")]
143    pub(crate) fn from_tonic(client: crate::exporter::tonic::trace::TonicTracesClient) -> Self {
144        SpanExporter {
145            client: SupportedTransportClient::Tonic(client),
146        }
147    }
148}
149
150impl opentelemetry_sdk::trace::SpanExporter for SpanExporter {
151    async fn export(&self, batch: Vec<SpanData>) -> OTelSdkResult {
152        match &self.client {
153            #[cfg(feature = "grpc-tonic")]
154            SupportedTransportClient::Tonic(client) => client.export(batch).await,
155            #[cfg(any(feature = "http-proto", feature = "http-json"))]
156            SupportedTransportClient::Http(client) => client.export(batch).await,
157        }
158    }
159
160    fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
161        match &mut self.client {
162            #[cfg(feature = "grpc-tonic")]
163            SupportedTransportClient::Tonic(client) => client.set_resource(resource),
164            #[cfg(any(feature = "http-proto", feature = "http-json"))]
165            SupportedTransportClient::Http(client) => client.set_resource(resource),
166        }
167    }
168}