1use crate::trace::SpanLimits;
12use opentelemetry::trace::{Event, Link, SpanContext, SpanId, SpanKind, Status};
13use opentelemetry::KeyValue;
14use std::borrow::Cow;
15use std::time::SystemTime;
16
17#[derive(Debug)]
19pub struct Span {
20 span_context: SpanContext,
21 data: Option<SpanData>,
22 tracer: crate::trace::Tracer,
23 span_limits: SpanLimits,
24}
25
26#[derive(Clone, Debug, PartialEq)]
27pub(crate) struct SpanData {
28 pub(crate) parent_span_id: SpanId,
30 pub(crate) span_kind: SpanKind,
32 pub(crate) name: Cow<'static, str>,
34 pub(crate) start_time: SystemTime,
36 pub(crate) end_time: SystemTime,
38 pub(crate) attributes: Vec<KeyValue>,
40 pub(crate) dropped_attributes_count: u32,
43 pub(crate) events: crate::trace::SpanEvents,
45 pub(crate) links: crate::trace::SpanLinks,
47 pub(crate) status: Status,
49}
50
51impl Span {
52 pub(crate) fn new(
53 span_context: SpanContext,
54 data: Option<SpanData>,
55 tracer: crate::trace::Tracer,
56 span_limit: SpanLimits,
57 ) -> Self {
58 Span {
59 span_context,
60 data,
61 tracer,
62 span_limits: span_limit,
63 }
64 }
65
66 fn with_data<T, F>(&mut self, f: F) -> Option<T>
68 where
69 F: FnOnce(&mut SpanData) -> T,
70 {
71 self.data.as_mut().map(f)
72 }
73
74 pub fn exported_data(&self) -> Option<crate::export::trace::SpanData> {
78 let (span_context, tracer) = (self.span_context.clone(), &self.tracer);
79
80 self.data
81 .as_ref()
82 .map(|data| build_export_data(data.clone(), span_context, tracer))
83 }
84}
85
86impl opentelemetry::trace::Span for Span {
87 fn add_event_with_timestamp<T>(
93 &mut self,
94 name: T,
95 timestamp: SystemTime,
96 mut attributes: Vec<KeyValue>,
97 ) where
98 T: Into<Cow<'static, str>>,
99 {
100 let span_events_limit = self.span_limits.max_events_per_span as usize;
101 let event_attributes_limit = self.span_limits.max_attributes_per_event as usize;
102 self.with_data(|data| {
103 if data.events.len() < span_events_limit {
104 let dropped_attributes_count =
105 attributes.len().saturating_sub(event_attributes_limit);
106 attributes.truncate(event_attributes_limit);
107
108 data.events.add_event(Event::new(
109 name,
110 timestamp,
111 attributes,
112 dropped_attributes_count as u32,
113 ));
114 } else {
115 data.events.dropped_count += 1;
116 }
117 });
118 }
119
120 fn span_context(&self) -> &SpanContext {
122 &self.span_context
123 }
124
125 fn is_recording(&self) -> bool {
129 self.data.is_some()
130 }
131
132 fn set_attribute(&mut self, attribute: KeyValue) {
138 let span_attribute_limit = self.span_limits.max_attributes_per_span as usize;
139 self.with_data(|data| {
140 if data.attributes.len() < span_attribute_limit {
141 data.attributes.push(attribute);
142 } else {
143 data.dropped_attributes_count += 1;
144 }
145 });
146 }
147
148 fn set_status(&mut self, status: Status) {
152 self.with_data(|data| {
153 if status > data.status {
156 data.status = status;
157 }
158 });
159 }
160
161 fn update_name<T>(&mut self, new_name: T)
163 where
164 T: Into<Cow<'static, str>>,
165 {
166 self.with_data(|data| {
167 data.name = new_name.into();
168 });
169 }
170
171 fn add_link(&mut self, span_context: SpanContext, attributes: Vec<KeyValue>) {
174 let span_links_limit = self.span_limits.max_links_per_span as usize;
175 let link_attributes_limit = self.span_limits.max_attributes_per_link as usize;
176 self.with_data(|data| {
177 if data.links.links.len() < span_links_limit {
178 let dropped_attributes_count =
179 attributes.len().saturating_sub(link_attributes_limit);
180 let mut attributes = attributes;
181 attributes.truncate(link_attributes_limit);
182 data.links.add_link(Link::new(
183 span_context,
184 attributes,
185 dropped_attributes_count as u32,
186 ));
187 } else {
188 data.links.dropped_count += 1;
189 }
190 });
191 }
192
193 fn end_with_timestamp(&mut self, timestamp: SystemTime) {
195 self.ensure_ended_and_exported(Some(timestamp));
196 }
197}
198
199impl Span {
200 fn ensure_ended_and_exported(&mut self, timestamp: Option<SystemTime>) {
201 let mut data = match self.data.take() {
203 Some(data) => data,
204 None => return,
205 };
206
207 let provider = self.tracer.provider();
208 if provider.is_shutdown() {
210 return;
211 }
212
213 if let Some(timestamp) = timestamp {
215 data.end_time = timestamp;
216 } else if data.end_time == data.start_time {
217 data.end_time = opentelemetry::time::now();
218 }
219
220 match provider.span_processors() {
221 [] => {}
222 [processor] => {
223 processor.on_end(build_export_data(
224 data,
225 self.span_context.clone(),
226 &self.tracer,
227 ));
228 }
229 processors => {
230 for processor in processors {
231 processor.on_end(build_export_data(
232 data.clone(),
233 self.span_context.clone(),
234 &self.tracer,
235 ));
236 }
237 }
238 }
239 }
240}
241
242impl Drop for Span {
243 fn drop(&mut self) {
245 self.ensure_ended_and_exported(None);
246 }
247}
248
249fn build_export_data(
250 data: SpanData,
251 span_context: SpanContext,
252 tracer: &crate::trace::Tracer,
253) -> crate::export::trace::SpanData {
254 crate::export::trace::SpanData {
255 span_context,
256 parent_span_id: data.parent_span_id,
257 span_kind: data.span_kind,
258 name: data.name,
259 start_time: data.start_time,
260 end_time: data.end_time,
261 attributes: data.attributes,
262 dropped_attributes_count: data.dropped_attributes_count,
263 events: data.events,
264 links: data.links,
265 status: data.status,
266 instrumentation_lib: tracer.instrumentation_library().clone(),
267 }
268}
269
270#[cfg(all(test, feature = "testing"))]
271mod tests {
272 use super::*;
273 use crate::testing::trace::NoopSpanExporter;
274 use crate::trace::span_limit::{
275 DEFAULT_MAX_ATTRIBUTES_PER_EVENT, DEFAULT_MAX_ATTRIBUTES_PER_LINK,
276 DEFAULT_MAX_ATTRIBUTES_PER_SPAN, DEFAULT_MAX_EVENT_PER_SPAN, DEFAULT_MAX_LINKS_PER_SPAN,
277 };
278 use crate::trace::{SpanEvents, SpanLinks};
279 use opentelemetry::trace::{self, SpanBuilder, TraceFlags, TraceId, Tracer};
280 use opentelemetry::{trace::Span as _, trace::TracerProvider};
281 use std::time::Duration;
282 use std::vec;
283
284 fn init() -> (crate::trace::Tracer, SpanData) {
285 let provider = crate::trace::TracerProvider::default();
286 let tracer = provider.tracer("opentelemetry");
287 let data = SpanData {
288 parent_span_id: SpanId::from_u64(0),
289 span_kind: trace::SpanKind::Internal,
290 name: "opentelemetry".into(),
291 start_time: opentelemetry::time::now(),
292 end_time: opentelemetry::time::now(),
293 attributes: Vec::new(),
294 dropped_attributes_count: 0,
295 events: SpanEvents::default(),
296 links: SpanLinks::default(),
297 status: Status::Unset,
298 };
299 (tracer, data)
300 }
301
302 fn create_span() -> Span {
303 let (tracer, data) = init();
304 Span::new(
305 SpanContext::empty_context(),
306 Some(data),
307 tracer,
308 Default::default(),
309 )
310 }
311
312 #[test]
313 fn create_span_without_data() {
314 let (tracer, _) = init();
315 let mut span = Span::new(
316 SpanContext::empty_context(),
317 None,
318 tracer,
319 Default::default(),
320 );
321 span.with_data(|_data| panic!("there are data"));
322 }
323
324 #[test]
325 fn create_span_with_data_mut() {
326 let (tracer, data) = init();
327 let mut span = Span::new(
328 SpanContext::empty_context(),
329 Some(data.clone()),
330 tracer,
331 Default::default(),
332 );
333 span.with_data(|d| assert_eq!(*d, data));
334 }
335
336 #[test]
337 fn add_event() {
338 let mut span = create_span();
339 let name = "some_event";
340 let attributes = vec![KeyValue::new("k", "v")];
341 span.add_event(name, attributes.clone());
342 span.with_data(|data| {
343 if let Some(event) = data.events.iter().next() {
344 assert_eq!(event.name, name);
345 assert_eq!(event.attributes, attributes);
346 } else {
347 panic!("no event");
348 }
349 });
350 }
351
352 #[test]
353 fn add_event_with_timestamp() {
354 let mut span = create_span();
355 let name = "some_event";
356 let attributes = vec![KeyValue::new("k", "v")];
357 let timestamp = opentelemetry::time::now();
358 span.add_event_with_timestamp(name, timestamp, attributes.clone());
359 span.with_data(|data| {
360 if let Some(event) = data.events.iter().next() {
361 assert_eq!(event.timestamp, timestamp);
362 assert_eq!(event.name, name);
363 assert_eq!(event.attributes, attributes);
364 } else {
365 panic!("no event");
366 }
367 });
368 }
369
370 #[test]
371 fn record_error() {
372 let mut span = create_span();
373 let err = std::io::Error::from(std::io::ErrorKind::Other);
374 span.record_error(&err);
375 span.with_data(|data| {
376 if let Some(event) = data.events.iter().next() {
377 assert_eq!(event.name, "exception");
378 assert_eq!(
379 event.attributes,
380 vec![KeyValue::new("exception.message", err.to_string())]
381 );
382 } else {
383 panic!("no event");
384 }
385 });
386 }
387
388 #[test]
389 fn set_attribute() {
390 let mut span = create_span();
391 let attributes = KeyValue::new("k", "v");
392 span.set_attribute(attributes.clone());
393 span.with_data(|data| {
394 let matching_attribute: Vec<&KeyValue> = data
395 .attributes
396 .iter()
397 .filter(|kv| kv.key.as_str() == attributes.key.as_str())
398 .collect();
399 if matching_attribute.len() == 1 {
400 assert_eq!(matching_attribute[0].value, attributes.value);
401 } else {
402 panic!("no attribute");
403 }
404 });
405 }
406
407 #[test]
408 fn set_attributes() {
409 let mut span = create_span();
410 let attributes = vec![KeyValue::new("k1", "v1"), KeyValue::new("k2", "v2")];
411 span.set_attributes(attributes);
412 span.with_data(|data| {
413 assert_eq!(data.attributes.len(), 2);
414 });
415 }
416
417 #[test]
418 fn set_status() {
419 {
420 let mut span = create_span();
421 let status = Status::Ok;
422 span.set_status(status.clone());
423 span.with_data(|data| assert_eq!(data.status, status));
424 }
425 {
426 let mut span = create_span();
427 let status = Status::Unset;
428 span.set_status(status.clone());
429 span.with_data(|data| assert_eq!(data.status, status));
430 }
431 {
432 let mut span = create_span();
433 let status = Status::error("error");
434 span.set_status(status.clone());
435 span.with_data(|data| assert_eq!(data.status, status));
436 }
437 {
438 let mut span = create_span();
439 span.set_status(Status::Ok);
441 span.set_status(Status::error("error"));
442 span.with_data(|data| assert_eq!(data.status, Status::Ok));
443 }
444 {
445 let mut span = create_span();
446 span.set_status(Status::Unset);
448 span.set_status(Status::error("error"));
449 span.with_data(|data| assert_ne!(data.status, Status::Ok));
450 }
451 }
452
453 #[test]
454 fn update_name() {
455 let mut span = create_span();
456 let name = "new_name";
457 span.update_name(name);
458 span.with_data(|data| {
459 assert_eq!(data.name, name);
460 });
461 }
462
463 #[test]
464 fn end() {
465 let mut span = create_span();
466 span.end();
467 }
468
469 #[test]
470 fn end_with_timestamp() {
471 let mut span = create_span();
472 let timestamp = opentelemetry::time::now();
473 span.end_with_timestamp(timestamp);
474 span.with_data(|data| assert_eq!(data.end_time, timestamp));
475 }
476
477 #[test]
478 fn allows_to_get_span_context_after_end() {
479 let mut span = create_span();
480 span.end();
481 assert_eq!(span.span_context(), &SpanContext::empty_context());
482 }
483
484 #[test]
485 fn end_only_once() {
486 let mut span = create_span();
487 let timestamp = opentelemetry::time::now();
488 span.end_with_timestamp(timestamp);
489 span.end_with_timestamp(timestamp.checked_add(Duration::from_secs(10)).unwrap());
490 span.with_data(|data| assert_eq!(data.end_time, timestamp));
491 }
492
493 #[test]
494 fn noop_after_end() {
495 let mut span = create_span();
496 let initial = span.with_data(|data| data.clone()).unwrap();
497 span.end();
498 span.add_event("some_event", vec![KeyValue::new("k", "v")]);
499 span.add_event_with_timestamp(
500 "some_event",
501 opentelemetry::time::now(),
502 vec![KeyValue::new("k", "v")],
503 );
504 let err = std::io::Error::from(std::io::ErrorKind::Other);
505 span.record_error(&err);
506 span.set_attribute(KeyValue::new("k", "v"));
507 span.set_status(Status::error("ERROR"));
508 span.update_name("new_name");
509 span.with_data(|data| {
510 assert_eq!(data.events, initial.events);
511 assert_eq!(data.attributes, initial.attributes);
512 assert_eq!(data.status, initial.status);
513 assert_eq!(data.name, initial.name);
514 });
515 }
516
517 #[test]
518 fn is_recording_true_when_not_ended() {
519 let span = create_span();
520 assert!(span.is_recording());
521 }
522
523 #[test]
524 fn is_recording_false_after_end() {
525 let mut span = create_span();
526 span.end();
527 assert!(!span.is_recording());
528 }
529
530 #[test]
531 fn exceed_span_attributes_limit() {
532 let exporter = NoopSpanExporter::new();
533 let provider_builder =
534 crate::trace::TracerProvider::builder().with_simple_exporter(exporter);
535 let provider = provider_builder.build();
536 let tracer = provider.tracer("opentelemetry-test");
537
538 let mut initial_attributes = Vec::new();
539 let mut expected_dropped_count = 1;
540 for i in 0..(DEFAULT_MAX_ATTRIBUTES_PER_SPAN + 1) {
541 initial_attributes.push(KeyValue::new(format!("key {}", i), i.to_string()))
542 }
543 let span_builder = SpanBuilder::from_name("test_span").with_attributes(initial_attributes);
544
545 let mut span = tracer.build(span_builder);
546 expected_dropped_count += 1;
547 span.set_attribute(KeyValue::new("key3", "value3"));
548
549 expected_dropped_count += 2;
550 let span_attributes_after_creation =
551 vec![KeyValue::new("foo", "1"), KeyValue::new("bar", "2")];
552 span.set_attributes(span_attributes_after_creation);
553
554 let actual_span = span
555 .data
556 .clone()
557 .expect("span data should not be empty as we already set it before");
558 assert_eq!(
559 actual_span.attributes.len(),
560 DEFAULT_MAX_ATTRIBUTES_PER_SPAN as usize,
561 "Span attributes should be truncated to the max limit"
562 );
563 assert_eq!(
564 actual_span.dropped_attributes_count, expected_dropped_count,
565 "Dropped count should match the actual count of attributes dropped"
566 );
567 }
568
569 #[test]
570 fn exceed_event_attributes_limit() {
571 let exporter = NoopSpanExporter::new();
572 let provider_builder =
573 crate::trace::TracerProvider::builder().with_simple_exporter(exporter);
574 let provider = provider_builder.build();
575 let tracer = provider.tracer("opentelemetry-test");
576
577 let mut event1 = Event::with_name("test event");
578 for i in 0..(DEFAULT_MAX_ATTRIBUTES_PER_EVENT * 2) {
579 event1
580 .attributes
581 .push(KeyValue::new(format!("key {}", i), i.to_string()))
582 }
583 let event2 = event1.clone();
584
585 let span_builder = tracer.span_builder("test").with_events(vec![event1]);
587 let mut span = tracer.build(span_builder);
588
589 span.add_event("another test event", event2.attributes);
591
592 let event_queue = span
593 .data
594 .clone()
595 .expect("span data should not be empty as we already set it before")
596 .events;
597 let event_vec: Vec<_> = event_queue.iter().take(2).collect();
598 #[allow(clippy::get_first)] let processed_event_1 = event_vec.get(0).expect("should have at least two events");
600 let processed_event_2 = event_vec.get(1).expect("should have at least two events");
601 assert_eq!(processed_event_1.attributes.len(), 128);
602 assert_eq!(processed_event_2.attributes.len(), 128);
603 }
604
605 #[test]
606 fn exceed_link_attributes_limit() {
607 let exporter = NoopSpanExporter::new();
608 let provider_builder =
609 crate::trace::TracerProvider::builder().with_simple_exporter(exporter);
610 let provider = provider_builder.build();
611 let tracer = provider.tracer("opentelemetry-test");
612
613 let mut link = Link::with_context(SpanContext::new(
614 TraceId::from_u128(12),
615 SpanId::from_u64(12),
616 TraceFlags::default(),
617 false,
618 Default::default(),
619 ));
620 for i in 0..(DEFAULT_MAX_ATTRIBUTES_PER_LINK * 2) {
621 link.attributes
622 .push(KeyValue::new(format!("key {}", i), i.to_string()));
623 }
624
625 let span_builder = tracer.span_builder("test").with_links(vec![link]);
626 let span = tracer.build(span_builder);
627 let link_queue = span
628 .data
629 .clone()
630 .expect("span data should not be empty as we already set it before")
631 .links;
632 let link_vec: Vec<_> = link_queue.links;
633 let processed_link = link_vec.first().expect("should have at least one link");
634 assert_eq!(processed_link.attributes.len(), 128);
635 }
636
637 #[test]
638 fn exceed_span_links_limit() {
639 let exporter = NoopSpanExporter::new();
640 let provider_builder =
641 crate::trace::TracerProvider::builder().with_simple_exporter(exporter);
642 let provider = provider_builder.build();
643 let tracer = provider.tracer("opentelemetry-test");
644
645 let mut links = Vec::new();
646 for _i in 0..(DEFAULT_MAX_LINKS_PER_SPAN * 2) {
647 links.push(Link::with_context(SpanContext::new(
648 TraceId::from_u128(12),
649 SpanId::from_u64(12),
650 TraceFlags::default(),
651 false,
652 Default::default(),
653 )))
654 }
655
656 let span_builder = tracer.span_builder("test").with_links(links);
657 let mut span = tracer.build(span_builder);
658
659 span.add_link(
661 SpanContext::new(
662 TraceId::from_u128(12),
663 SpanId::from_u64(12),
664 TraceFlags::default(),
665 false,
666 Default::default(),
667 ),
668 vec![],
669 );
670 let link_queue = span
671 .data
672 .clone()
673 .expect("span data should not be empty as we already set it before")
674 .links;
675 let link_vec: Vec<_> = link_queue.links;
676 assert_eq!(link_vec.len(), DEFAULT_MAX_LINKS_PER_SPAN as usize);
677 }
678
679 #[test]
680 fn exceed_span_events_limit() {
681 let exporter = NoopSpanExporter::new();
682 let provider_builder =
683 crate::trace::TracerProvider::builder().with_simple_exporter(exporter);
684 let provider = provider_builder.build();
685 let tracer = provider.tracer("opentelemetry-test");
686
687 let mut events = Vec::new();
688 for _i in 0..(DEFAULT_MAX_EVENT_PER_SPAN * 2) {
689 events.push(Event::with_name("test event"))
690 }
691
692 let span_builder = tracer.span_builder("test").with_events(events);
694 let mut span = tracer.build(span_builder);
695
696 span.add_event("test event again, after span builder", Vec::new());
698 span.add_event("test event once again, after span builder", Vec::new());
699 let span_events = span
700 .data
701 .clone()
702 .expect("span data should not be empty as we already set it before")
703 .events;
704 let event_vec: Vec<_> = span_events.events;
705 assert_eq!(event_vec.len(), DEFAULT_MAX_EVENT_PER_SPAN as usize);
706 }
707
708 #[test]
709 fn test_span_exported_data() {
710 let provider = crate::trace::TracerProvider::builder()
711 .with_simple_exporter(NoopSpanExporter::new())
712 .build();
713 let tracer = provider.tracer("test");
714
715 let mut span = tracer.start("test_span");
716 span.add_event("test_event", vec![]);
717 span.set_status(Status::error(""));
718
719 let exported_data = span.exported_data();
720 assert!(exported_data.is_some());
721
722 provider.shutdown().expect("shutdown panicked");
723 let dropped_span = tracer.start("span_with_dropped_provider");
724 assert!(dropped_span.exported_data().is_none());
726 }
727}