revoke_trace/
exporter.rs

1use opentelemetry_sdk::trace::TraceError;
2use std::time::Duration;
3
4/// 导出器配置
5#[derive(Debug, Clone)]
6pub struct ExporterConfig {
7    /// 导出端点
8    pub endpoint: String,
9    /// 导出超时
10    pub timeout: Duration,
11    /// 是否使用 TLS
12    pub use_tls: bool,
13    /// 自定义头部
14    pub headers: Vec<(String, String)>,
15}
16
17impl Default for ExporterConfig {
18    fn default() -> Self {
19        Self {
20            endpoint: "http://localhost:4317".to_string(),
21            timeout: Duration::from_secs(10),
22            use_tls: false,
23            headers: Vec::new(),
24        }
25    }
26}
27
28/// 追踪导出器
29pub enum TraceExporter {
30    #[cfg(feature = "otlp")]
31    Otlp,
32    /// 控制台导出器(用于调试)
33    Console,
34    /// 无操作导出器
35    Noop,
36}
37
38impl TraceExporter {
39    /// 创建 OTLP 导出器
40    #[cfg(feature = "otlp")]
41    pub fn otlp(_config: ExporterConfig) -> Self {
42        Self::Otlp
43    }
44
45
46    /// 创建控制台导出器
47    pub fn console() -> Self {
48        Self::Console
49    }
50
51    /// 创建无操作导出器
52    pub fn noop() -> Self {
53        Self::Noop
54    }
55
56    /// 构建导出器
57    pub async fn build(
58        self,
59        service_name: &str,
60    ) -> Result<opentelemetry_sdk::trace::Tracer, TraceError> {
61        use opentelemetry::KeyValue;
62        use opentelemetry::trace::TracerProvider;
63        use opentelemetry_sdk::Resource;
64
65        let resource = Resource::builder()
66            .with_service_name(service_name.to_string())
67            .with_attribute(KeyValue::new("service.version", env!("CARGO_PKG_VERSION")))
68            .build();
69
70        match self {
71            #[cfg(feature = "otlp")]
72            Self::Otlp => {
73                use opentelemetry_otlp::WithExportConfig;
74
75                opentelemetry_otlp::SpanExporter::builder()
76                    .with_tonic()
77                    .with_endpoint("http://localhost:4317")
78                    .build()
79                    .map_err(|e| TraceError::Other(Box::new(e)))
80                    .and_then(|exporter| {
81                        let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
82                            .with_batch_exporter(exporter)
83                            .with_resource(resource)
84                            .build();
85                        Ok(provider.tracer(service_name.to_string()))
86                    })
87            }
88            Self::Console => {
89                // 使用简单的 TracerProvider
90                let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
91                    .with_resource(resource)
92                    .build();
93
94                Ok(provider.tracer(service_name.to_string()))
95            }
96            Self::Noop => {
97                // 创建一个空的 provider
98                let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
99                    .with_resource(resource)
100                    .build();
101                Ok(provider.tracer(service_name.to_string()))
102            }
103        }
104    }
105}
106
107/// 导出器构建器
108pub struct ExporterBuilder {
109    config: ExporterConfig,
110}
111
112impl ExporterBuilder {
113    /// 创建新的构建器
114    pub fn new() -> Self {
115        Self {
116            config: ExporterConfig::default(),
117        }
118    }
119
120    /// 设置端点
121    pub fn with_endpoint(mut self, endpoint: impl Into<String>) -> Self {
122        self.config.endpoint = endpoint.into();
123        self
124    }
125
126    /// 设置超时
127    pub fn with_timeout(mut self, timeout: Duration) -> Self {
128        self.config.timeout = timeout;
129        self
130    }
131
132    /// 启用 TLS
133    pub fn with_tls(mut self, use_tls: bool) -> Self {
134        self.config.use_tls = use_tls;
135        self
136    }
137
138    /// 添加自定义头部
139    pub fn with_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
140        self.config.headers.push((key.into(), value.into()));
141        self
142    }
143
144    /// 构建 OTLP 导出器
145    #[cfg(feature = "otlp")]
146    pub fn build_otlp(self) -> TraceExporter {
147        TraceExporter::otlp(self.config)
148    }
149
150    /// 构建控制台导出器
151    pub fn build_console(self) -> TraceExporter {
152        TraceExporter::console()
153    }
154}
155
156impl Default for ExporterBuilder {
157    fn default() -> Self {
158        Self::new()
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn test_exporter_config() {
168        let config = ExporterConfig {
169            endpoint: "http://localhost:4318".to_string(),
170            timeout: Duration::from_secs(30),
171            use_tls: true,
172            ..Default::default()
173        };
174
175        assert_eq!(config.endpoint, "http://localhost:4318");
176        assert_eq!(config.timeout, Duration::from_secs(30));
177        assert!(config.use_tls);
178    }
179
180    #[test]
181    fn test_exporter_builder() {
182        let exporter = ExporterBuilder::new()
183            .with_endpoint("http://custom:4317")
184            .with_timeout(Duration::from_secs(20))
185            .with_tls(true)
186            .with_header("Authorization", "Bearer token")
187            .build_console();
188
189        match exporter {
190            TraceExporter::Console => {
191                // 正确构建了控制台导出器
192            }
193            _ => panic!("Expected console exporter"),
194        }
195    }
196}