1use crate::sdk::trace::SpanLimits;
12use crate::trace::{Event, SpanContext, SpanId, SpanKind, StatusCode};
13use crate::{sdk, trace, KeyValue};
14use std::borrow::Cow;
15use std::sync::Arc;
16use std::time::SystemTime;
17
18#[derive(Debug)]
20pub struct Span {
21 span_context: SpanContext,
22 data: Option<SpanData>,
23 tracer: sdk::trace::Tracer,
24 span_limits: SpanLimits,
25}
26
27#[derive(Clone, Debug, PartialEq)]
28pub(crate) struct SpanData {
29 pub(crate) parent_span_id: SpanId,
31 pub(crate) span_kind: SpanKind,
33 pub(crate) name: Cow<'static, str>,
35 pub(crate) start_time: SystemTime,
37 pub(crate) end_time: SystemTime,
39 pub(crate) attributes: sdk::trace::EvictedHashMap,
41 pub(crate) events: sdk::trace::EvictedQueue<trace::Event>,
43 pub(crate) links: sdk::trace::EvictedQueue<trace::Link>,
45 pub(crate) status_code: StatusCode,
47 pub(crate) status_message: Cow<'static, str>,
49}
50
51impl Span {
52 pub(crate) fn new(
53 span_context: SpanContext,
54 data: Option<SpanData>,
55 tracer: sdk::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::sdk::export::trace::SpanData> {
78 let (span_context, tracer) = (self.span_context.clone(), &self.tracer);
79 let resource = if let Some(provider) = self.tracer.provider() {
80 provider.config().resource.clone()
81 } else {
82 None
83 };
84 self.data
85 .as_ref()
86 .map(|data| build_export_data(data.clone(), span_context, resource, tracer))
87 }
88}
89
90impl crate::trace::Span for Span {
91 fn add_event_with_timestamp<T>(
97 &mut self,
98 name: T,
99 timestamp: SystemTime,
100 mut attributes: Vec<KeyValue>,
101 ) where
102 T: Into<Cow<'static, str>>,
103 {
104 let event_attributes_limit = self.span_limits.max_attributes_per_event as usize;
105 self.with_data(|data| {
106 let dropped_attributes_count = attributes.len().saturating_sub(event_attributes_limit);
107 attributes.truncate(event_attributes_limit);
108
109 data.events.push_back(Event::new(
110 name,
111 timestamp,
112 attributes,
113 dropped_attributes_count as u32,
114 ))
115 });
116 }
117
118 fn span_context(&self) -> &SpanContext {
120 &self.span_context
121 }
122
123 fn is_recording(&self) -> bool {
127 self.data.is_some()
128 }
129
130 fn set_attribute(&mut self, attribute: KeyValue) {
136 self.with_data(|data| {
137 data.attributes.insert(attribute);
138 });
139 }
140
141 fn set_status(&mut self, code: StatusCode, message: String) {
144 self.with_data(|data| {
145 if code.priority() < data.status_code.priority() {
147 return;
149 }
150 if code == StatusCode::Error {
151 data.status_message = message.into();
152 }
153 data.status_code = code;
154 });
155 }
156
157 fn update_name<T>(&mut self, new_name: T)
159 where
160 T: Into<Cow<'static, str>>,
161 {
162 self.with_data(|data| {
163 data.name = new_name.into();
164 });
165 }
166
167 fn end_with_timestamp(&mut self, timestamp: SystemTime) {
169 self.ensure_ended_and_exported(Some(timestamp));
170 }
171}
172
173impl Span {
174 fn ensure_ended_and_exported(&mut self, timestamp: Option<SystemTime>) {
175 let mut data = match self.data.take() {
177 Some(data) => data,
178 None => return,
179 };
180
181 let provider = match self.tracer.provider() {
183 Some(provider) => provider,
184 None => return,
185 };
186
187 if let Some(timestamp) = timestamp {
189 data.end_time = timestamp;
190 } else if data.end_time == data.start_time {
191 data.end_time = crate::time::now();
192 }
193
194 match provider.span_processors().as_slice() {
195 [] => {}
196 [processor] => {
197 processor.on_end(build_export_data(
198 data,
199 self.span_context.clone(),
200 provider.config().resource.clone(),
201 &self.tracer,
202 ));
203 }
204 processors => {
205 let config = provider.config();
206 for processor in processors {
207 processor.on_end(build_export_data(
208 data.clone(),
209 self.span_context.clone(),
210 config.resource.clone(),
211 &self.tracer,
212 ));
213 }
214 }
215 }
216 }
217}
218
219impl Drop for Span {
220 fn drop(&mut self) {
222 self.ensure_ended_and_exported(None);
223 }
224}
225
226fn build_export_data(
227 data: SpanData,
228 span_context: SpanContext,
229 resource: Option<Arc<sdk::Resource>>,
230 tracer: &sdk::trace::Tracer,
231) -> sdk::export::trace::SpanData {
232 sdk::export::trace::SpanData {
233 span_context,
234 parent_span_id: data.parent_span_id,
235 span_kind: data.span_kind,
236 name: data.name,
237 start_time: data.start_time,
238 end_time: data.end_time,
239 attributes: data.attributes,
240 events: data.events,
241 links: data.links,
242 status_code: data.status_code,
243 status_message: data.status_message,
244 resource,
245 instrumentation_lib: tracer.instrumentation_library().clone(),
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use crate::sdk::trace::span_limit::{
253 DEFAULT_MAX_ATTRIBUTES_PER_EVENT, DEFAULT_MAX_ATTRIBUTES_PER_LINK,
254 };
255 use crate::trace::{noop::NoopSpanExporter, Link, TraceFlags, TraceId, Tracer};
256 use crate::{trace::Span as _, trace::TracerProvider, KeyValue};
257 use std::time::Duration;
258
259 fn init() -> (sdk::trace::Tracer, SpanData) {
260 let provider = sdk::trace::TracerProvider::default();
261 let config = provider.config();
262 let tracer = provider.tracer("opentelemetry");
263 let data = SpanData {
264 parent_span_id: SpanId::from_u64(0),
265 span_kind: trace::SpanKind::Internal,
266 name: "opentelemetry".into(),
267 start_time: crate::time::now(),
268 end_time: crate::time::now(),
269 attributes: sdk::trace::EvictedHashMap::new(
270 config.span_limits.max_attributes_per_span,
271 0,
272 ),
273 events: sdk::trace::EvictedQueue::new(config.span_limits.max_events_per_span),
274 links: sdk::trace::EvictedQueue::new(config.span_limits.max_links_per_span),
275 status_code: StatusCode::Unset,
276 status_message: "".into(),
277 };
278 (tracer, data)
279 }
280
281 fn create_span() -> Span {
282 let (tracer, data) = init();
283 Span::new(
284 SpanContext::empty_context(),
285 Some(data),
286 tracer,
287 Default::default(),
288 )
289 }
290
291 #[test]
292 fn create_span_without_data() {
293 let (tracer, _) = init();
294 let mut span = Span::new(
295 SpanContext::empty_context(),
296 None,
297 tracer,
298 Default::default(),
299 );
300 span.with_data(|_data| panic!("there are data"));
301 }
302
303 #[test]
304 fn create_span_with_data_mut() {
305 let (tracer, data) = init();
306 let mut span = Span::new(
307 SpanContext::empty_context(),
308 Some(data.clone()),
309 tracer,
310 Default::default(),
311 );
312 span.with_data(|d| assert_eq!(*d, data));
313 }
314
315 #[test]
316 fn add_event() {
317 let mut span = create_span();
318 let name = "some_event".to_string();
319 let attributes = vec![KeyValue::new("k", "v")];
320 span.add_event(name.clone(), attributes.clone());
321 span.with_data(|data| {
322 if let Some(event) = data.events.iter().next() {
323 assert_eq!(event.name, name);
324 assert_eq!(event.attributes, attributes);
325 } else {
326 panic!("no event");
327 }
328 });
329 }
330
331 #[test]
332 fn add_event_with_timestamp() {
333 let mut span = create_span();
334 let name = "some_event".to_string();
335 let attributes = vec![KeyValue::new("k", "v")];
336 let timestamp = crate::time::now();
337 span.add_event_with_timestamp(name.clone(), timestamp, attributes.clone());
338 span.with_data(|data| {
339 if let Some(event) = data.events.iter().next() {
340 assert_eq!(event.timestamp, timestamp);
341 assert_eq!(event.name, name);
342 assert_eq!(event.attributes, attributes);
343 } else {
344 panic!("no event");
345 }
346 });
347 }
348
349 #[test]
350 fn record_exception() {
351 let mut span = create_span();
352 let err = std::io::Error::from(std::io::ErrorKind::Other);
353 span.record_exception(&err);
354 span.with_data(|data| {
355 if let Some(event) = data.events.iter().next() {
356 assert_eq!(event.name, "exception");
357 assert_eq!(
358 event.attributes,
359 vec![KeyValue::new("exception.message", err.to_string())]
360 );
361 } else {
362 panic!("no event");
363 }
364 });
365 }
366
367 #[test]
368 fn record_exception_with_stacktrace() {
369 let mut span = create_span();
370 let err = std::io::Error::from(std::io::ErrorKind::Other);
371 let stacktrace = "stacktrace...".to_string();
372 span.record_exception_with_stacktrace(&err, stacktrace.clone());
373 span.with_data(|data| {
374 if let Some(event) = data.events.iter().next() {
375 assert_eq!(event.name, "exception");
376 assert_eq!(
377 event.attributes,
378 vec![
379 KeyValue::new("exception.message", err.to_string()),
380 KeyValue::new("exception.stacktrace", stacktrace),
381 ]
382 );
383 } else {
384 panic!("no event");
385 }
386 });
387 }
388
389 #[test]
390 fn set_attribute() {
391 let mut span = create_span();
392 let attributes = KeyValue::new("k", "v");
393 span.set_attribute(attributes.clone());
394 span.with_data(|data| {
395 if let Some(val) = data.attributes.get(&attributes.key) {
396 assert_eq!(*val, attributes.value);
397 } else {
398 panic!("no attribute");
399 }
400 });
401 }
402
403 #[test]
404 fn set_status() {
405 {
406 let mut span = create_span();
407 let status = StatusCode::Ok;
408 let message = "OK".to_string();
409 span.set_status(status, message);
410 span.with_data(|data| {
411 assert_eq!(data.status_code, status);
412 assert_eq!(data.status_message, "");
413 });
414 }
415 {
416 let mut span = create_span();
417 let status = StatusCode::Unset;
418 let message = "OK".to_string();
419 span.set_status(status, message);
420 span.with_data(|data| {
421 assert_eq!(data.status_code, status);
422 assert_eq!(data.status_message, "");
423 });
424 }
425 {
426 let mut span = create_span();
427 let status = StatusCode::Error;
428 let message = "Error".to_string();
429 span.set_status(status, message);
430 span.with_data(|data| {
431 assert_eq!(data.status_code, status);
432 assert_eq!(data.status_message, "Error");
433 });
434 }
435 {
436 let mut span = create_span();
437 span.set_status(StatusCode::Ok, "".to_string());
439 span.set_status(StatusCode::Error, "error".to_string());
440 span.with_data(|data| {
441 assert_eq!(data.status_code, StatusCode::Ok);
442 assert_eq!(data.status_message, "");
443 });
444 }
445 {
446 let mut span = create_span();
447 span.set_status(StatusCode::Error, "error".to_string());
449 span.with_data(|data| {
450 assert_eq!(data.status_code, StatusCode::Error);
451 assert_eq!(data.status_message, "error");
452 });
453 }
454 }
455
456 #[test]
457 fn update_name() {
458 let mut span = create_span();
459 let name = "new_name".to_string();
460 span.update_name(name.clone());
461 span.with_data(|data| {
462 assert_eq!(data.name, name);
463 });
464 }
465
466 #[test]
467 fn end() {
468 let mut span = create_span();
469 span.end();
470 }
471
472 #[test]
473 fn end_with_timestamp() {
474 let mut span = create_span();
475 let timestamp = crate::time::now();
476 span.end_with_timestamp(timestamp);
477 span.with_data(|data| assert_eq!(data.end_time, timestamp));
478 }
479
480 #[test]
481 fn allows_to_get_span_context_after_end() {
482 let mut span = create_span();
483 span.end();
484 assert_eq!(span.span_context(), &SpanContext::empty_context());
485 }
486
487 #[test]
488 fn end_only_once() {
489 let mut span = create_span();
490 let timestamp = crate::time::now();
491 span.end_with_timestamp(timestamp);
492 span.end_with_timestamp(timestamp.checked_add(Duration::from_secs(10)).unwrap());
493 span.with_data(|data| assert_eq!(data.end_time, timestamp));
494 }
495
496 #[test]
497 fn noop_after_end() {
498 let mut span = create_span();
499 let initial = span.with_data(|data| data.clone()).unwrap();
500 span.end();
501 span.add_event("some_event".to_string(), vec![KeyValue::new("k", "v")]);
502 span.add_event_with_timestamp(
503 "some_event".to_string(),
504 crate::time::now(),
505 vec![KeyValue::new("k", "v")],
506 );
507 let err = std::io::Error::from(std::io::ErrorKind::Other);
508 span.record_exception(&err);
509 span.record_exception_with_stacktrace(&err, "stacktrace...".to_string());
510 span.set_attribute(KeyValue::new("k", "v"));
511 span.set_status(StatusCode::Error, "ERROR".to_string());
512 span.update_name("new_name".to_string());
513 span.with_data(|data| {
514 assert_eq!(data.events, initial.events);
515 assert_eq!(data.attributes, initial.attributes);
516 assert_eq!(data.status_code, initial.status_code);
517 assert_eq!(data.status_message, initial.status_message);
518 assert_eq!(data.name, initial.name);
519 });
520 }
521
522 #[test]
523 fn is_recording_true_when_not_ended() {
524 let span = create_span();
525 assert!(span.is_recording());
526 }
527
528 #[test]
529 fn is_recording_false_after_end() {
530 let mut span = create_span();
531 span.end();
532 assert!(!span.is_recording());
533 }
534
535 #[test]
536 fn exceed_event_attributes_limit() {
537 let exporter = NoopSpanExporter::new();
538 let provider_builder = sdk::trace::TracerProvider::builder().with_simple_exporter(exporter);
539 let provider = provider_builder.build();
540 let tracer = provider.tracer("opentelemetry-test");
541
542 let mut event1 = Event::with_name("test event");
543 for i in 0..(DEFAULT_MAX_ATTRIBUTES_PER_EVENT * 2) {
544 event1
545 .attributes
546 .push(KeyValue::new(format!("key {}", i), i.to_string()))
547 }
548 let event2 = event1.clone();
549
550 let span_builder = tracer.span_builder("test").with_events(vec![event1]);
552 let mut span = tracer.build(span_builder);
553
554 span.add_event("another test event", event2.attributes);
556
557 let event_queue = span
558 .data
559 .clone()
560 .expect("span data should not be empty as we already set it before")
561 .events;
562 let event_vec: Vec<_> = event_queue.iter().take(2).collect();
563 let processed_event_1 = event_vec.get(0).expect("should have at least two events");
564 let processed_event_2 = event_vec.get(1).expect("should have at least two events");
565 assert_eq!(processed_event_1.attributes.len(), 128);
566 assert_eq!(processed_event_2.attributes.len(), 128);
567 }
568
569 #[test]
570 fn exceed_link_attributes_limit() {
571 let exporter = NoopSpanExporter::new();
572 let provider_builder = sdk::trace::TracerProvider::builder().with_simple_exporter(exporter);
573 let provider = provider_builder.build();
574 let tracer = provider.tracer("opentelemetry-test");
575
576 let mut link = Link::new(
577 SpanContext::new(
578 TraceId::from_u128(12),
579 SpanId::from_u64(12),
580 TraceFlags::default(),
581 false,
582 Default::default(),
583 ),
584 Vec::new(),
585 );
586 for i in 0..(DEFAULT_MAX_ATTRIBUTES_PER_LINK * 2) {
587 link.attributes
588 .push(KeyValue::new(format!("key {}", i), i.to_string()));
589 }
590
591 let span_builder = tracer.span_builder("test").with_links(vec![link]);
592 let span = tracer.build(span_builder);
593 let link_queue = span
594 .data
595 .clone()
596 .expect("span data should not be empty as we already set it before")
597 .links;
598 let link_vec: Vec<_> = link_queue.iter().collect();
599 let processed_link = link_vec.get(0).expect("should have at least one link");
600 assert_eq!(processed_link.attributes().len(), 128);
601 }
602
603 #[test]
604 fn test_span_exported_data() {
605 let provider = sdk::trace::TracerProvider::builder()
606 .with_simple_exporter(NoopSpanExporter::new())
607 .build();
608 let tracer = provider.tracer("test");
609
610 let mut span = tracer.start("test_span");
611 span.add_event("test_event".to_string(), vec![]);
612 span.set_status(StatusCode::Error, "".to_string());
613
614 let exported_data = span.exported_data();
615 assert!(exported_data.is_some());
616
617 drop(provider);
618 let dropped_span = tracer.start("span_with_dropped_provider");
619 assert!(dropped_span.exported_data().is_none());
621 }
622}