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