1mod config;
10mod events;
11mod export;
12mod id_generator;
13mod links;
14mod provider;
15mod sampler;
16mod span;
17mod span_limit;
18mod span_processor;
19#[cfg(feature = "experimental_trace_batch_span_processor_with_async_runtime")]
20pub mod span_processor_with_async_runtime;
22mod tracer;
23
24pub use config::{config, Config};
25pub use events::SpanEvents;
26pub use export::{SpanData, SpanExporter};
27
28#[cfg(any(feature = "testing", test))]
30#[cfg_attr(docsrs, doc(cfg(any(feature = "testing", test))))]
31pub mod in_memory_exporter;
32#[cfg(any(feature = "testing", test))]
33#[cfg_attr(docsrs, doc(cfg(any(feature = "testing", test))))]
34pub use in_memory_exporter::{InMemorySpanExporter, InMemorySpanExporterBuilder};
35
36pub use id_generator::{IdGenerator, RandomIdGenerator};
37pub use links::SpanLinks;
38pub use provider::{SdkTracerProvider, TracerProviderBuilder};
39pub use sampler::{Sampler, ShouldSample};
40pub use span::Span;
41pub use span_limit::SpanLimits;
42pub use span_processor::{
43 BatchConfig, BatchConfigBuilder, BatchSpanProcessor, BatchSpanProcessorBuilder,
44 SimpleSpanProcessor, SpanProcessor,
45};
46
47pub use tracer::SdkTracer;
48pub use tracer::SdkTracer as Tracer; #[cfg(feature = "jaeger_remote_sampler")]
51pub use sampler::{JaegerRemoteSampler, JaegerRemoteSamplerBuilder};
52
53#[cfg(feature = "experimental_trace_batch_span_processor_with_async_runtime")]
54#[cfg(test)]
55mod runtime_tests;
56
57#[cfg(all(test, feature = "testing"))]
58mod tests {
59
60 use super::*;
61 use crate::{
62 trace::span_limit::{DEFAULT_MAX_EVENT_PER_SPAN, DEFAULT_MAX_LINKS_PER_SPAN},
63 trace::{InMemorySpanExporter, InMemorySpanExporterBuilder},
64 };
65 use opentelemetry::trace::{
66 SamplingDecision, SamplingResult, SpanKind, Status, TraceContextExt, TraceState,
67 };
68 use opentelemetry::{testing::trace::TestSpan, InstrumentationScope};
69 use opentelemetry::{
70 trace::{
71 Event, Link, Span, SpanBuilder, SpanContext, SpanId, TraceFlags, TraceId, Tracer,
72 TracerProvider,
73 },
74 Context, KeyValue,
75 };
76
77 #[test]
78 fn tracer_in_span() {
79 let exporter = InMemorySpanExporterBuilder::new().build();
81 let provider = SdkTracerProvider::builder()
82 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
83 .build();
84
85 let tracer = provider.tracer("test_tracer");
87 tracer.in_span("span_name", |cx| {
88 let span = cx.span();
89 assert!(span.is_recording());
90 span.update_name("span_name_updated");
91 span.set_attribute(KeyValue::new("attribute1", "value1"));
92 span.add_event("test-event".to_string(), vec![]);
93 });
94
95 let exported_spans = exporter
97 .get_finished_spans()
98 .expect("Spans are expected to be exported.");
99 assert_eq!(exported_spans.len(), 1);
100 let span = &exported_spans[0];
101 assert_eq!(span.name, "span_name_updated");
102 assert_eq!(span.instrumentation_scope.name(), "test_tracer");
103 assert_eq!(span.attributes.len(), 1);
104 assert_eq!(span.events.len(), 1);
105 assert_eq!(span.events[0].name, "test-event");
106 assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
107 assert!(!span.span_context.is_remote());
108 assert_eq!(span.status, Status::Unset);
109 }
110
111 #[test]
112 fn tracer_start() {
113 let exporter = InMemorySpanExporterBuilder::new().build();
115 let provider = SdkTracerProvider::builder()
116 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
117 .build();
118
119 let tracer = provider.tracer("test_tracer");
121 let mut span = tracer.start("span_name");
122 span.set_attribute(KeyValue::new("attribute1", "value1"));
123 span.add_event("test-event".to_string(), vec![]);
124 span.set_status(Status::error("cancelled"));
125 span.end();
126
127 span.update_name("span_name_updated");
129
130 let exported_spans = exporter
132 .get_finished_spans()
133 .expect("Spans are expected to be exported.");
134 assert_eq!(exported_spans.len(), 1);
135 let span = &exported_spans[0];
136 assert_eq!(span.name, "span_name");
137 assert_eq!(span.instrumentation_scope.name(), "test_tracer");
138 assert_eq!(span.attributes.len(), 1);
139 assert_eq!(span.events.len(), 1);
140 assert_eq!(span.events[0].name, "test-event");
141 assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
142 assert!(!span.span_context.is_remote());
143 let status_expected = Status::error("cancelled");
144 assert_eq!(span.status, status_expected);
145 }
146
147 #[test]
148 fn tracer_span_builder() {
149 let exporter = InMemorySpanExporterBuilder::new().build();
151 let provider = SdkTracerProvider::builder()
152 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
153 .build();
154
155 let tracer = provider.tracer("test_tracer");
157 let mut span = tracer
158 .span_builder("span_name")
159 .with_kind(SpanKind::Server)
160 .start(&tracer);
161 span.set_attribute(KeyValue::new("attribute1", "value1"));
162 span.add_event("test-event".to_string(), vec![]);
163 span.set_status(Status::Ok);
164 drop(span);
165
166 let exported_spans = exporter
168 .get_finished_spans()
169 .expect("Spans are expected to be exported.");
170 assert_eq!(exported_spans.len(), 1);
171 let span = &exported_spans[0];
172 assert_eq!(span.name, "span_name");
173 assert_eq!(span.span_kind, SpanKind::Server);
174 assert_eq!(span.instrumentation_scope.name(), "test_tracer");
175 assert_eq!(span.attributes.len(), 1);
176 assert_eq!(span.events.len(), 1);
177 assert_eq!(span.events[0].name, "test-event");
178 assert_eq!(span.span_context.trace_flags(), TraceFlags::SAMPLED);
179 assert!(!span.span_context.is_remote());
180 assert_eq!(span.status, Status::Ok);
181 }
182
183 #[test]
184 fn exceed_span_links_limit() {
185 let exporter = InMemorySpanExporterBuilder::new().build();
187 let provider = SdkTracerProvider::builder()
188 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
189 .build();
190
191 let tracer = provider.tracer("test_tracer");
193
194 let mut links = Vec::new();
195 for _i in 0..(DEFAULT_MAX_LINKS_PER_SPAN * 2) {
196 links.push(Link::with_context(SpanContext::new(
197 TraceId::from_u128(12),
198 SpanId::from_u64(12),
199 TraceFlags::default(),
200 false,
201 Default::default(),
202 )))
203 }
204
205 let span_builder = SpanBuilder::from_name("span_name").with_links(links);
206 let mut span = tracer.build(span_builder);
207 span.end();
208
209 let exported_spans = exporter
211 .get_finished_spans()
212 .expect("Spans are expected to be exported.");
213 assert_eq!(exported_spans.len(), 1);
214 let span = &exported_spans[0];
215 assert_eq!(span.name, "span_name");
216 assert_eq!(span.links.len(), DEFAULT_MAX_LINKS_PER_SPAN as usize);
217 }
218
219 #[test]
220 fn exceed_span_events_limit() {
221 let exporter = InMemorySpanExporterBuilder::new().build();
223 let provider = SdkTracerProvider::builder()
224 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
225 .build();
226
227 let tracer = provider.tracer("test_tracer");
229
230 let mut events = Vec::new();
231 for _i in 0..(DEFAULT_MAX_EVENT_PER_SPAN * 2) {
232 events.push(Event::with_name("test event"))
233 }
234
235 let span_builder = SpanBuilder::from_name("span_name").with_events(events);
237 let mut span = tracer.build(span_builder);
238
239 span.add_event("test event again, after span builder", Vec::new());
241 span.add_event("test event once again, after span builder", Vec::new());
242 span.end();
243
244 let exported_spans = exporter
246 .get_finished_spans()
247 .expect("Spans are expected to be exported.");
248 assert_eq!(exported_spans.len(), 1);
249 let span = &exported_spans[0];
250 assert_eq!(span.name, "span_name");
251 assert_eq!(span.events.len(), DEFAULT_MAX_EVENT_PER_SPAN as usize);
252 assert_eq!(span.events.dropped_count, DEFAULT_MAX_EVENT_PER_SPAN + 2);
253 }
254
255 #[test]
256 fn trace_state_for_dropped_sampler() {
257 let exporter = InMemorySpanExporterBuilder::new().build();
258 let provider = SdkTracerProvider::builder()
259 .with_sampler(Sampler::AlwaysOff)
260 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
261 .build();
262
263 let tracer = provider.tracer("test");
264 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
265
266 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
267 TraceId::from_u128(10000),
268 SpanId::from_u64(20),
269 TraceFlags::SAMPLED,
270 true,
271 trace_state.clone(),
272 )));
273
274 let span = tracer.start_with_context("span", &parent_context);
275 assert_eq!(
276 span.span_context().trace_state().get("foo"),
277 trace_state.get("foo")
278 )
279 }
280
281 #[derive(Clone, Debug, Default)]
282 struct TestRecordOnlySampler {}
283
284 impl ShouldSample for TestRecordOnlySampler {
285 fn should_sample(
286 &self,
287 parent_context: Option<&Context>,
288 _trace_id: TraceId,
289 _name: &str,
290 _span_kind: &SpanKind,
291 _attributes: &[KeyValue],
292 _links: &[Link],
293 ) -> SamplingResult {
294 let trace_state = parent_context
295 .unwrap()
296 .span()
297 .span_context()
298 .trace_state()
299 .clone();
300 SamplingResult {
301 decision: SamplingDecision::RecordOnly,
302 attributes: vec![KeyValue::new("record_only_key", "record_only_value")],
303 trace_state,
304 }
305 }
306 }
307
308 #[test]
309 fn trace_state_for_record_only_sampler() {
310 let exporter = InMemorySpanExporterBuilder::new().build();
311 let provider = SdkTracerProvider::builder()
312 .with_sampler(TestRecordOnlySampler::default())
313 .with_span_processor(SimpleSpanProcessor::new(Box::new(exporter.clone())))
314 .build();
315
316 let tracer = provider.tracer("test");
317 let trace_state = TraceState::from_key_value(vec![("foo", "bar")]).unwrap();
318
319 let parent_context = Context::new().with_span(TestSpan(SpanContext::new(
320 TraceId::from_u128(10000),
321 SpanId::from_u64(20),
322 TraceFlags::SAMPLED,
323 true,
324 trace_state.clone(),
325 )));
326
327 let span = tracer.build_with_context(
328 SpanBuilder::from_name("span")
329 .with_attributes(vec![KeyValue::new("extra_attr_key", "extra_attr_value")]),
330 &parent_context,
331 );
332 assert!(!span.span_context().trace_flags().is_sampled());
333 assert_eq!(
334 span.exported_data().unwrap().attributes,
335 vec![
336 KeyValue::new("extra_attr_key", "extra_attr_value"),
337 KeyValue::new("record_only_key", "record_only_value")
338 ]
339 );
340 assert_eq!(span.span_context().trace_state().get("foo"), Some("bar"));
341 }
342
343 #[test]
344 fn tracer_attributes() {
345 let provider = SdkTracerProvider::builder().build();
346 let scope = InstrumentationScope::builder("basic")
347 .with_attributes(vec![KeyValue::new("test_k", "test_v")])
348 .build();
349
350 let tracer = provider.tracer_with_scope(scope);
351 let instrumentation_scope = tracer.instrumentation_scope();
352 assert!(instrumentation_scope
353 .attributes()
354 .eq(&[KeyValue::new("test_k", "test_v")]));
355 }
356
357 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
358 async fn empty_tracer_name_retained() {
359 async fn tracer_name_retained_helper(
360 tracer: super::SdkTracer,
361 provider: SdkTracerProvider,
362 exporter: InMemorySpanExporter,
363 ) {
364 tracer.start("my_span").end();
366
367 assert!(provider.force_flush().is_ok());
369
370 let finished_spans = exporter
372 .get_finished_spans()
373 .expect("spans are expected to be exported.");
374 assert_eq!(finished_spans.len(), 1, "There should be a single span");
375
376 let tracer_name = finished_spans[0].instrumentation_scope.name();
377 assert_eq!(tracer_name, "", "The tracer name should be an empty string");
378
379 exporter.reset();
380 }
381
382 let exporter = InMemorySpanExporter::default();
383 let span_processor = SimpleSpanProcessor::new(Box::new(exporter.clone()));
384 let tracer_provider = SdkTracerProvider::builder()
385 .with_span_processor(span_processor)
386 .build();
387
388 let tracer1 = tracer_provider.tracer("");
390 tracer_name_retained_helper(tracer1, tracer_provider.clone(), exporter.clone()).await;
391
392 let tracer_scope = InstrumentationScope::builder("").build();
393 let tracer2 = tracer_provider.tracer_with_scope(tracer_scope);
394 tracer_name_retained_helper(tracer2, tracer_provider, exporter).await;
395 }
396}