apollo_opentelemetry/macros/
span.rs1#[doc(hidden)]
11#[macro_export]
12macro_rules! __attr_to_option {
13 ($value:literal) => {
15 Some($crate::__private::opentelemetry::Value::from($value))
16 };
17 ($value:expr) => {
19 $crate::ToValue::to_value(&$value)
20 };
21}
22
23#[macro_export]
49macro_rules! span_attr {
50 ($($key:literal = $value:expr),+ $(,)?) => {{
51 use $crate::__private::opentelemetry::trace::{TraceContextExt as _};
52 $(
53 if let Some(__attr_val) = $crate::ToValue::to_value(&$value) {
54 $crate::__private::opentelemetry::Context::current().span().set_attribute(
55 $crate::__private::opentelemetry::KeyValue::new($key, __attr_val),
56 );
57 }
58 )+
59 }};
60}
61
62#[macro_export]
80macro_rules! span_err {
81 ($($arg:tt)*) => {{
82 use $crate::__private::opentelemetry::trace::{Status, TraceContextExt as _};
83 $crate::__private::opentelemetry::Context::current().span().set_status(Status::error(format!($($arg)*)));
84 }};
85}
86
87#[macro_export]
103macro_rules! span_ok {
104 () => {{
105 use $crate::__private::opentelemetry::trace::{Status, TraceContextExt as _};
106 $crate::__private::opentelemetry::Context::current()
107 .span()
108 .set_status(Status::Ok);
109 }};
110}
111
112#[cfg(test)]
113mod tests {
114 use crate::span;
115
116 use apollo_opentelemetry_test::{TelemetryContext, assert_spans_snapshot};
117 use opentelemetry::trace::SpanKind;
118
119 #[test]
120 fn test_span_simple() {
121 let ctx = TelemetryContext::new();
122 drop(span!("simple"));
123 assert_spans_snapshot!(ctx, @r#"
124 - name: simple
125 span_kind: Internal
126 is_sampled: true
127 "#);
128 }
129
130 #[test]
131 fn test_span_with_kind() {
132 let ctx = TelemetryContext::new();
133 drop(span!("with-kind", kind: SpanKind::Server));
134 assert_spans_snapshot!(ctx, @r#"
135 - name: with-kind
136 span_kind: Server
137 is_sampled: true
138 "#);
139 }
140
141 #[test]
142 fn test_span_with_attributes() {
143 let ctx = TelemetryContext::new();
144 drop(span!("with-attrs", "key" = "value", "count" = 42i64));
145 assert_spans_snapshot!(ctx, @r#"
146 - name: with-attrs
147 span_kind: Internal
148 is_sampled: true
149 attributes:
150 count: "42"
151 key: value
152 "#);
153 }
154
155 #[test]
156 fn test_span_with_kind_and_attributes() {
157 let ctx = TelemetryContext::new();
158 drop(span!("full", kind: SpanKind::Client, "method" = "GET"));
159 assert_spans_snapshot!(ctx, @r#"
160 - name: full
161 span_kind: Client
162 is_sampled: true
163 attributes:
164 method: GET
165 "#);
166 }
167
168 #[test]
171 fn test_span_expr_name_variable() {
172 let ctx = TelemetryContext::new();
173 let name = String::from("expr-name");
174 drop(span!(name));
175 assert_spans_snapshot!(ctx, @r#"
176 - name: expr-name
177 span_kind: Internal
178 is_sampled: true
179 "#);
180 }
181
182 #[test]
183 fn test_span_expr_name_format() {
184 let ctx = TelemetryContext::new();
185 let id = 42;
186 drop(span!(format!("span-{}", id)));
187 assert_spans_snapshot!(ctx, @r#"
188 - name: span-42
189 span_kind: Internal
190 is_sampled: true
191 "#);
192 }
193
194 #[test]
195 fn test_span_expr_name_with_kind() {
196 let ctx = TelemetryContext::new();
197 let name = "dynamic-name";
198 drop(span!(name.to_string(), kind: SpanKind::Server));
199 assert_spans_snapshot!(ctx, @r#"
200 - name: dynamic-name
201 span_kind: Server
202 is_sampled: true
203 "#);
204 }
205
206 #[test]
207 fn test_span_expr_name_with_attributes() {
208 let ctx = TelemetryContext::new();
209 let name = String::from("expr-attrs");
210 drop(span!(name, "key" = "value"));
211 assert_spans_snapshot!(ctx, @r#"
212 - name: expr-attrs
213 span_kind: Internal
214 is_sampled: true
215 attributes:
216 key: value
217 "#);
218 }
219
220 #[test]
221 fn test_span_expr_name_closure() {
222 let ctx = TelemetryContext::new();
223 let name = String::from("expr-closure");
224 span!(name, || {
225 });
227 assert_spans_snapshot!(ctx, @r#"
228 - name: expr-closure
229 span_kind: Internal
230 is_sampled: true
231 "#);
232 }
233
234 #[tokio::test]
235 async fn test_span_expr_name_async() {
236 let ctx = TelemetryContext::new();
237 let id = 123;
238 span!(format!("async-{}", id), async {
239 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
240 })
241 .await;
242 assert_spans_snapshot!(ctx, @r#"
243 - name: async-123
244 span_kind: Internal
245 is_sampled: true
246 "#);
247 }
248
249 fn test_scope() -> &'static opentelemetry::InstrumentationScope {
250 static SCOPE: std::sync::LazyLock<opentelemetry::InstrumentationScope> =
251 std::sync::LazyLock::new(|| {
252 opentelemetry::InstrumentationScope::builder("my-component").build()
253 });
254 &SCOPE
255 }
256
257 #[tokio::test]
258 async fn test_span_in_async() {
259 let ctx = TelemetryContext::new();
260
261 let span = span!("async-operation");
262 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
263 drop(span);
264
265 assert_spans_snapshot!(ctx, @r#"
266 - name: async-operation
267 span_kind: Internal
268 is_sampled: true
269 "#);
270 }
271
272 #[tokio::test]
273 async fn test_span_context_propagation() {
274 use opentelemetry::Context;
275 use opentelemetry::trace::{FutureExt as _, TraceContextExt};
276
277 let ctx = TelemetryContext::new();
278
279 let parent_span = span!("parent");
280 let parent_cx = Context::current_with_span(parent_span);
281
282 async {
283 tokio::spawn(
284 async {
285 drop(span!("child"));
286 }
287 .with_current_context(),
288 )
289 .await
290 .unwrap();
291 }
292 .with_context(parent_cx)
293 .await;
294
295 assert_spans_snapshot!(ctx, @r#"
296 - name: child
297 span_kind: Internal
298 has_parent: true
299 is_sampled: true
300 - name: parent
301 span_kind: Internal
302 is_sampled: true
303 "#);
304 }
305
306 #[test]
309 fn test_span_closure_simple() {
310 let ctx = TelemetryContext::new();
311 span!("closure-simple", || {
312 });
314 assert_spans_snapshot!(ctx, @r#"
315 - name: closure-simple
316 span_kind: Internal
317 is_sampled: true
318 "#);
319 }
320
321 #[test]
322 fn test_span_closure_with_kind() {
323 let ctx = TelemetryContext::new();
324 span!("closure-kind", kind: SpanKind::Server, || {
325 });
327 assert_spans_snapshot!(ctx, @r#"
328 - name: closure-kind
329 span_kind: Server
330 is_sampled: true
331 "#);
332 }
333
334 #[test]
335 fn test_span_closure_with_attributes() {
336 let ctx = TelemetryContext::new();
337 span!("closure-attrs", "key" = "value", || {
338 });
340 assert_spans_snapshot!(ctx, @r#"
341 - name: closure-attrs
342 span_kind: Internal
343 is_sampled: true
344 attributes:
345 key: value
346 "#);
347 }
348
349 #[test]
350 fn test_span_closure_with_kind_and_attributes() {
351 let ctx = TelemetryContext::new();
352 span!("closure-full", kind: SpanKind::Client, "method" = "GET", || {
353 });
355 assert_spans_snapshot!(ctx, @r#"
356 - name: closure-full
357 span_kind: Client
358 is_sampled: true
359 attributes:
360 method: GET
361 "#);
362 }
363
364 #[test]
365 fn test_span_closure_returns_value() {
366 let ctx = TelemetryContext::new();
367 let result = span!("closure-return", || 42);
368 assert_eq!(result, 42);
369 assert_spans_snapshot!(ctx, @r#"
370 - name: closure-return
371 span_kind: Internal
372 is_sampled: true
373 "#);
374 }
375
376 #[test]
377 fn test_span_move_closure() {
378 let ctx = TelemetryContext::new();
379 let value = String::from("captured");
380 let result = span!("move-closure", move || {
381 value });
383 assert_eq!(result, "captured");
384 assert_spans_snapshot!(ctx, @r#"
385 - name: move-closure
386 span_kind: Internal
387 is_sampled: true
388 "#);
389 }
390
391 #[test]
392 fn test_span_closure_nested() {
393 let ctx = TelemetryContext::new();
394 span!("outer", || {
395 span!("inner", || {
396 });
398 });
399 assert_spans_snapshot!(ctx, @r#"
400 - name: inner
401 span_kind: Internal
402 has_parent: true
403 is_sampled: true
404 - name: outer
405 span_kind: Internal
406 is_sampled: true
407 "#);
408 }
409
410 #[test]
411 fn test_span_closure_with_span_event() {
412 use crate::span_event;
413
414 let ctx = TelemetryContext::new();
415 span!("with-event", || {
416 span_event!("something-happened");
417 });
418 assert_spans_snapshot!(ctx, @r#"
419 - name: with-event
420 span_kind: Internal
421 is_sampled: true
422 events:
423 - name: something-happened
424 "#);
425 }
426
427 #[tokio::test]
430 async fn test_span_async_block_simple() {
431 let ctx = TelemetryContext::new();
432 span!("async-simple", async {
433 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
434 })
435 .await;
436 assert_spans_snapshot!(ctx, @r#"
437 - name: async-simple
438 span_kind: Internal
439 is_sampled: true
440 "#);
441 }
442
443 #[tokio::test]
444 async fn test_span_async_block_with_kind() {
445 let ctx = TelemetryContext::new();
446 span!("async-kind", kind: SpanKind::Server, async {
447 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
448 })
449 .await;
450 assert_spans_snapshot!(ctx, @r#"
451 - name: async-kind
452 span_kind: Server
453 is_sampled: true
454 "#);
455 }
456
457 #[tokio::test]
458 async fn test_span_async_block_with_attributes() {
459 let ctx = TelemetryContext::new();
460 span!("async-attrs", "key" = "value", async {
461 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
462 })
463 .await;
464 assert_spans_snapshot!(ctx, @r#"
465 - name: async-attrs
466 span_kind: Internal
467 is_sampled: true
468 attributes:
469 key: value
470 "#);
471 }
472
473 #[tokio::test]
474 async fn test_span_async_block_with_kind_and_attributes() {
475 let ctx = TelemetryContext::new();
476 span!("async-full", kind: SpanKind::Client, "method" = "GET", async {
477 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
478 })
479 .await;
480 assert_spans_snapshot!(ctx, @r#"
481 - name: async-full
482 span_kind: Client
483 is_sampled: true
484 attributes:
485 method: GET
486 "#);
487 }
488
489 #[tokio::test]
490 async fn test_span_async_block_returns_value() {
491 let ctx = TelemetryContext::new();
492 let result = span!("async-return", async {
493 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
494 42
495 })
496 .await;
497 assert_eq!(result, 42);
498 assert_spans_snapshot!(ctx, @r#"
499 - name: async-return
500 span_kind: Internal
501 is_sampled: true
502 "#);
503 }
504
505 #[tokio::test]
506 async fn test_span_async_block_nested() {
507 let ctx = TelemetryContext::new();
508 span!("async-outer", async {
509 span!("async-inner", async {
510 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
511 })
512 .await;
513 })
514 .await;
515 assert_spans_snapshot!(ctx, @r#"
516 - name: async-inner
517 span_kind: Internal
518 has_parent: true
519 is_sampled: true
520 - name: async-outer
521 span_kind: Internal
522 is_sampled: true
523 "#);
524 }
525
526 #[tokio::test]
527 async fn test_span_async_move_block() {
528 let ctx = TelemetryContext::new();
529 let value = String::from("captured");
530 let result = span!("async-move", async move {
531 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
532 value })
534 .await;
535 assert_eq!(result, "captured");
536 assert_spans_snapshot!(ctx, @r#"
537 - name: async-move
538 span_kind: Internal
539 is_sampled: true
540 "#);
541 }
542
543 #[tokio::test]
544 async fn test_span_async_block_with_span_event() {
545 use crate::span_event;
546
547 let ctx = TelemetryContext::new();
548 span!("async-with-event", async {
549 span_event!("async-event");
550 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
551 })
552 .await;
553 assert_spans_snapshot!(ctx, @r#"
554 - name: async-with-event
555 span_kind: Internal
556 is_sampled: true
557 events:
558 - name: async-event
559 "#);
560 }
561
562 #[tokio::test]
563 async fn test_span_async_block_spawned_task() {
564 let ctx = TelemetryContext::new();
568 span!("parent", async {
569 tokio::spawn(span!("spawned-child", async {
570 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
571 }))
572 .await
573 .unwrap();
574 })
575 .await;
576 assert_spans_snapshot!(ctx, @r#"
577 - name: spawned-child
578 span_kind: Internal
579 has_parent: true
580 is_sampled: true
581 - name: parent
582 span_kind: Internal
583 is_sampled: true
584 "#);
585 }
586
587 #[test]
590 fn test_span_with_optional_attribute_some() {
591 let ctx = TelemetryContext::new();
592 let value: Option<i64> = Some(42);
593 drop(span!("opt-some", "count" = value));
594 assert_spans_snapshot!(ctx, @r#"
595 - name: opt-some
596 span_kind: Internal
597 is_sampled: true
598 attributes:
599 count: "42"
600 "#);
601 }
602
603 #[test]
604 fn test_span_with_optional_attribute_none() {
605 let ctx = TelemetryContext::new();
606 let value: Option<i64> = None;
607 drop(span!("opt-none", "count" = value));
608 assert_spans_snapshot!(ctx, @r#"
609 - name: opt-none
610 span_kind: Internal
611 is_sampled: true
612 "#);
613 }
614
615 #[test]
616 fn test_span_with_mixed_optional_attributes() {
617 let ctx = TelemetryContext::new();
618 let present: Option<&str> = Some("hello");
619 let absent: Option<i64> = None;
620 drop(span!(
621 "mixed-opts",
622 "present" = present,
623 "absent" = absent,
624 "always" = "here"
625 ));
626 assert_spans_snapshot!(ctx, @r#"
627 - name: mixed-opts
628 span_kind: Internal
629 is_sampled: true
630 attributes:
631 always: here
632 present: hello
633 "#);
634 }
635
636 #[test]
639 fn test_span_attr_single() {
640 let ctx = TelemetryContext::new();
641 span!("with-post-attr", || {
642 span_attr!("post.attr" = 123i64);
643 });
644 assert_spans_snapshot!(ctx, @r#"
645 - name: with-post-attr
646 span_kind: Internal
647 is_sampled: true
648 attributes:
649 post.attr: "123"
650 "#);
651 }
652
653 #[test]
654 fn test_span_attr_multiple() {
655 let ctx = TelemetryContext::new();
656 span!("with-multi-attr", || {
657 span_attr!("key1" = "value1", "key2" = 42i64);
658 });
659 assert_spans_snapshot!(ctx, @r#"
660 - name: with-multi-attr
661 span_kind: Internal
662 is_sampled: true
663 attributes:
664 key1: value1
665 key2: "42"
666 "#);
667 }
668
669 #[test]
670 fn test_span_attr_none_skipped() {
671 let ctx = TelemetryContext::new();
672 span!("with-skipped-attr", || {
673 span_attr!("skipped" = None::<i64>);
674 });
675 assert_spans_snapshot!(ctx, @r#"
676 - name: with-skipped-attr
677 span_kind: Internal
678 is_sampled: true
679 "#);
680 }
681
682 #[test]
683 fn test_span_attr_mixed_some_none() {
684 let ctx = TelemetryContext::new();
685 let present: Option<&str> = Some("hello");
686 let absent: Option<i64> = None;
687 span!("mixed-attr", || {
688 span_attr!("present" = present, "absent" = absent, "direct" = "value");
689 });
690 assert_spans_snapshot!(ctx, @r#"
691 - name: mixed-attr
692 span_kind: Internal
693 is_sampled: true
694 attributes:
695 direct: value
696 present: hello
697 "#);
698 }
699
700 #[test]
701 fn test_span_attr_trailing_comma() {
702 let ctx = TelemetryContext::new();
703 span!("trailing-comma", || {
704 span_attr!("key" = "value",);
705 });
706 assert_spans_snapshot!(ctx, @r#"
707 - name: trailing-comma
708 span_kind: Internal
709 is_sampled: true
710 attributes:
711 key: value
712 "#);
713 }
714
715 #[test]
718 fn test_span_err_simple() {
719 let ctx = TelemetryContext::new();
720 span!("with-error", || {
721 span_err!("something went wrong");
722 });
723 assert_spans_snapshot!(ctx, @r#"
724 - name: with-error
725 span_kind: Internal
726 is_sampled: true
727 status: "Error: something went wrong"
728 "#);
729 }
730
731 #[test]
732 fn test_span_err_formatted() {
733 let ctx = TelemetryContext::new();
734 let id = 42;
735 let reason = "not found";
736 span!("with-formatted-error", || {
737 span_err!("failed to process id {}: {}", id, reason);
738 });
739 assert_spans_snapshot!(ctx, @r#"
740 - name: with-formatted-error
741 span_kind: Internal
742 is_sampled: true
743 status: "Error: failed to process id 42: not found"
744 "#);
745 }
746
747 #[test]
750 fn test_span_ok() {
751 let ctx = TelemetryContext::new();
752 span!("with-ok", || {
753 span_ok!();
754 });
755 assert_spans_snapshot!(ctx, @r#"
756 - name: with-ok
757 span_kind: Internal
758 is_sampled: true
759 status: Ok
760 "#);
761 }
762
763 #[test]
766 fn test_span_closure_result_ok() {
767 let ctx = TelemetryContext::new();
768 let result: Result<i32, &str> = span!("result-ok", || Ok(42));
769 assert_eq!(result, Ok(42));
770 assert_spans_snapshot!(ctx, @r#"
771 - name: result-ok
772 span_kind: Internal
773 is_sampled: true
774 status: Ok
775 "#);
776 }
777
778 #[test]
779 fn test_span_closure_result_err() {
780 let ctx = TelemetryContext::new();
781 let result: Result<i32, &str> = span!("result-err", || Err("something failed"));
782 assert_eq!(result, Err("something failed"));
783 assert_spans_snapshot!(ctx, @r#"
784 - name: result-err
785 span_kind: Internal
786 is_sampled: true
787 status: "Error: something failed"
788 "#);
789 }
790
791 #[test]
792 fn test_span_closure_non_result() {
793 let ctx = TelemetryContext::new();
794 let value: i32 = span!("non-result", || 42);
795 assert_eq!(value, 42);
796 assert_spans_snapshot!(ctx, @r#"
798 - name: non-result
799 span_kind: Internal
800 is_sampled: true
801 "#);
802 }
803
804 #[test]
805 fn test_span_closure_custom_result_alias() {
806 type MyResult<T> = Result<T, Box<dyn std::error::Error>>;
807
808 let ctx = TelemetryContext::new();
809 let result: MyResult<&str> = span!("custom-result", || Ok("success"));
810 assert!(result.is_ok());
811 assert_spans_snapshot!(ctx, @r#"
812 - name: custom-result
813 span_kind: Internal
814 is_sampled: true
815 status: Ok
816 "#);
817 }
818
819 #[tokio::test]
820 async fn test_span_async_block_result_ok() {
821 let ctx = TelemetryContext::new();
822 let result: Result<i32, &str> = span!("async-result-ok", async { Ok(42) }).await;
823 assert_eq!(result, Ok(42));
824 assert_spans_snapshot!(ctx, @r#"
825 - name: async-result-ok
826 span_kind: Internal
827 is_sampled: true
828 status: Ok
829 "#);
830 }
831
832 #[tokio::test]
833 async fn test_span_async_block_result_err() {
834 let ctx = TelemetryContext::new();
835 let result: Result<i32, &str> =
836 span!("async-result-err", async { Err("async failure") }).await;
837 assert_eq!(result, Err("async failure"));
838 assert_spans_snapshot!(ctx, @r#"
839 - name: async-result-err
840 span_kind: Internal
841 is_sampled: true
842 status: "Error: async failure"
843 "#);
844 }
845
846 #[tokio::test]
847 async fn test_span_async_block_non_result() {
848 let ctx = TelemetryContext::new();
849 let value: i32 = span!("async-non-result", async { 42 }).await;
850 assert_eq!(value, 42);
851 assert_spans_snapshot!(ctx, @r#"
853 - name: async-non-result
854 span_kind: Internal
855 is_sampled: true
856 "#);
857 }
858
859 #[test]
860 fn test_span_closure_question_mark_sets_error_status() {
861 fn fallible() -> Result<(), &'static str> {
862 Err("inner error")
863 }
864
865 let ctx = TelemetryContext::new();
866 let result: Result<(), &str> = span!("with-question-mark", || {
868 fallible()?;
869 Ok(())
870 });
871 assert_eq!(result, Err("inner error"));
872 assert_spans_snapshot!(ctx, @r#"
873 - name: with-question-mark
874 span_kind: Internal
875 is_sampled: true
876 status: "Error: inner error"
877 "#);
878 }
879
880 #[tokio::test]
881 async fn test_span_async_block_question_mark_sets_error_status() {
882 async fn fallible() -> Result<(), &'static str> {
883 Err("async inner error")
884 }
885
886 let ctx = TelemetryContext::new();
887 let result: Result<(), &str> = span!("async-with-question-mark", async {
888 fallible().await?;
889 Ok(())
890 })
891 .await;
892 assert_eq!(result, Err("async inner error"));
893 assert_spans_snapshot!(ctx, @r#"
895 - name: async-with-question-mark
896 span_kind: Internal
897 is_sampled: true
898 status: "Error: async inner error"
899 "#);
900 }
901
902 #[test]
905 fn test_span_with_explicit_parent_return_form() {
906 use opentelemetry::Context;
907 use opentelemetry::trace::TraceContextExt;
908
909 let ctx = TelemetryContext::new();
910
911 let parent_span = span!("parent");
913 let parent_cx = Context::current_with_span(parent_span);
914
915 drop(span!("child", parent: &parent_cx));
917
918 drop(parent_cx);
920
921 assert_spans_snapshot!(ctx, @r#"
922 - name: child
923 span_kind: Internal
924 has_parent: true
925 is_sampled: true
926 - name: parent
927 span_kind: Internal
928 is_sampled: true
929 "#);
930 }
931
932 #[test]
933 fn test_span_with_explicit_parent_closure() {
934 use opentelemetry::Context;
935 use opentelemetry::trace::TraceContextExt;
936
937 let ctx = TelemetryContext::new();
938
939 let parent_span = span!("parent");
940 let parent_cx = Context::current_with_span(parent_span);
941
942 span!("child", parent: &parent_cx, || {
943 });
945
946 drop(parent_cx);
947
948 assert_spans_snapshot!(ctx, @r#"
949 - name: child
950 span_kind: Internal
951 has_parent: true
952 is_sampled: true
953 - name: parent
954 span_kind: Internal
955 is_sampled: true
956 "#);
957 }
958
959 #[test]
960 fn test_span_with_explicit_parent_kind_attributes_and_scope() {
961 use opentelemetry::Context;
962 use opentelemetry::trace::TraceContextExt;
963
964 let ctx = TelemetryContext::new();
965
966 let parent_span = span!("parent");
967 let parent_cx = Context::current_with_span(parent_span);
968
969 span!(
970 "child",
971 scope: test_scope(),
972 parent: &parent_cx,
973 kind: SpanKind::Server,
974 "http.method" = "GET",
975 || {
976 }
978 );
979 drop(parent_cx);
980
981 assert_spans_snapshot!(ctx, @r#"
982 - name: child
983 span_kind: Server
984 has_parent: true
985 is_sampled: true
986 attributes:
987 http.method: GET
988 - name: parent
989 span_kind: Internal
990 is_sampled: true
991 "#);
992
993 let spans = ctx.spans();
994 let child = spans.iter().find(|s| s.name == "child").unwrap();
995 assert_eq!(child.instrumentation_scope.name(), "my-component");
996 }
997
998 #[tokio::test]
999 async fn test_span_with_explicit_parent_async() {
1000 use opentelemetry::Context;
1001 use opentelemetry::trace::TraceContextExt;
1002
1003 let ctx = TelemetryContext::new();
1004
1005 let parent_span = span!("parent");
1006 let parent_cx = Context::current_with_span(parent_span);
1007
1008 span!("child", parent: &parent_cx, async {
1009 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
1010 })
1011 .await;
1012
1013 drop(parent_cx);
1014
1015 assert_spans_snapshot!(ctx, @r#"
1016 - name: child
1017 span_kind: Internal
1018 has_parent: true
1019 is_sampled: true
1020 - name: parent
1021 span_kind: Internal
1022 is_sampled: true
1023 "#);
1024 }
1025
1026 #[tokio::test]
1027 async fn test_span_with_explicit_parent_spawned_task() {
1028 use opentelemetry::Context;
1029 use opentelemetry::trace::TraceContextExt;
1030
1031 let ctx = TelemetryContext::new();
1032
1033 let parent_span = span!("parent");
1035 let parent_cx = Context::current_with_span(parent_span);
1036
1037 tokio::spawn(span!("spawned-child", parent: &parent_cx, async move {
1040 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
1041 }))
1042 .await
1043 .unwrap();
1044
1045 drop(parent_cx);
1046
1047 assert_spans_snapshot!(ctx, @r#"
1048 - name: spawned-child
1049 span_kind: Internal
1050 has_parent: true
1051 is_sampled: true
1052 - name: parent
1053 span_kind: Internal
1054 is_sampled: true
1055 "#);
1056 }
1057}