1use std::collections::HashMap;23use opentelemetry_otlp::tonic_types::metadata::MetadataMap;4use opentelemetry_otlp::{5 LogExporter, MetricExporter, SpanExporter, WithExportConfig as _, WithHttpConfig as _,6 WithTonicConfig as _,7};89use crate::{Error, OtlpProtocol, ResolvedOtlpSettings};1011fn parse_headers(headers: &str) -> impl Iterator<Item = (&str, &str)> {12 headers.split(',').map(|header| {13 let mut parts = header.splitn(2, '=');14 let key = parts.next().unwrap();15 let value = parts.next().unwrap_or("");16 (key, value)17 })18}1920fn to_metadata_map(headers: Option<&str>) -> MetadataMap {21 headers22 .map(|headers| {23 MetadataMap::from_headers(24 parse_headers(headers)25 .map(|(key, value)| (key.parse().unwrap(), value.parse().unwrap()))26 .collect(),27 )28 })29 .unwrap_or_default()30}3132fn to_hashmap(headers: Option<&str>) -> HashMap<String, String> {33 headers34 .map(|headers| {35 parse_headers(headers)36 .map(|(key, value)| (key.into(), value.into()))37 .collect()38 })39 .unwrap_or_default()40}4142macro_rules! build_exporter {43 ($exporter:ty, $settings:expr) => {{44 let s: &ResolvedOtlpSettings = $settings;45 match s.protocol {46 OtlpProtocol::Grpc => {47 let mut builder = <$exporter>::builder()48 .with_tonic()49 .with_endpoint(&s.endpoint)50 .with_metadata(to_metadata_map(s.headers.as_deref()))51 .with_protocol(s.protocol.into())52 .with_timeout(s.timeout);53 if let Some(compression) = s.compression {54 builder = builder.with_compression(compression.into());55 }56 builder.build()57 }58 OtlpProtocol::HttpProtobuf | OtlpProtocol::HttpJson => {59 <$exporter>::builder()60 .with_http()61 .with_endpoint(&s.endpoint)62 .with_headers(to_hashmap(s.headers.as_deref()))63 .with_protocol(s.protocol.into())64 .with_timeout(s.timeout)65 .build()66 }67 }68 }};69}7071impl ResolvedOtlpSettings {72 pub fn span_exporter(&self) -> Result<SpanExporter, Error> {73 Ok(build_exporter!(SpanExporter, self)?)74 }7576 pub fn log_exporter(&self) -> Result<LogExporter, Error> {77 Ok(build_exporter!(LogExporter, self)?)78 }7980 pub fn metric_exporter(&self) -> Result<MetricExporter, Error> {81 Ok(build_exporter!(MetricExporter, self)?)82 }83}