spin_world/wasi_otel/
trace_conversions.rs1use crate::wasi;
2use opentelemetry_sdk::trace::{SpanEvents, SpanLinks};
3
4impl From<wasi::otel::tracing::SpanData> for opentelemetry_sdk::trace::SpanData {
5 fn from(value: wasi::otel::tracing::SpanData) -> Self {
6 let mut span_events = SpanEvents::default();
7 span_events.events = value.events.into_iter().map(Into::into).collect();
8 span_events.dropped_count = value.dropped_events;
9 let mut span_links = SpanLinks::default();
10 span_links.links = value.links.into_iter().map(Into::into).collect();
11 span_links.dropped_count = value.dropped_links;
12 Self {
13 span_context: value.span_context.into(),
14 parent_span_id: opentelemetry::trace::SpanId::from_hex(&value.parent_span_id)
15 .unwrap_or(opentelemetry::trace::SpanId::INVALID),
16 span_kind: value.span_kind.into(),
17 name: value.name.into(),
18 start_time: value.start_time.into(),
19 end_time: value.end_time.into(),
20 attributes: value.attributes.into_iter().map(Into::into).collect(),
21 dropped_attributes_count: value.dropped_attributes,
22 events: span_events,
23 links: span_links,
24 status: value.status.into(),
25 instrumentation_scope: value.instrumentation_scope.into(),
26 }
27 }
28}
29
30impl From<wasi::otel::tracing::SpanContext> for opentelemetry::trace::SpanContext {
31 fn from(sc: wasi::otel::tracing::SpanContext) -> Self {
32 let trace_id = opentelemetry::trace::TraceId::from_hex(&sc.trace_id)
33 .unwrap_or(opentelemetry::trace::TraceId::INVALID);
34 let span_id = opentelemetry::trace::SpanId::from_hex(&sc.span_id)
35 .unwrap_or(opentelemetry::trace::SpanId::INVALID);
36 let trace_state = opentelemetry::trace::TraceState::from_key_value(sc.trace_state)
37 .unwrap_or_else(|_| opentelemetry::trace::TraceState::default());
38 Self::new(
39 trace_id,
40 span_id,
41 sc.trace_flags.into(),
42 sc.is_remote,
43 trace_state,
44 )
45 }
46}
47
48impl From<opentelemetry::trace::SpanContext> for wasi::otel::tracing::SpanContext {
49 fn from(sc: opentelemetry::trace::SpanContext) -> Self {
50 Self {
51 trace_id: format!("{:x}", sc.trace_id()),
52 span_id: format!("{:x}", sc.span_id()),
53 trace_flags: sc.trace_flags().into(),
54 is_remote: sc.is_remote(),
55 trace_state: sc
56 .trace_state()
57 .header()
58 .split(',')
59 .filter_map(|s| {
60 if let Some((key, value)) = s.split_once('=') {
61 Some((key.to_string(), value.to_string()))
62 } else {
63 None
64 }
65 })
66 .collect(),
67 }
68 }
69}
70
71impl From<wasi::otel::tracing::TraceFlags> for opentelemetry::trace::TraceFlags {
72 fn from(flags: wasi::otel::tracing::TraceFlags) -> Self {
73 Self::new(flags.as_array()[0] as u8)
74 }
75}
76
77impl From<opentelemetry::trace::TraceFlags> for wasi::otel::tracing::TraceFlags {
78 fn from(flags: opentelemetry::trace::TraceFlags) -> Self {
79 if flags.is_sampled() {
80 wasi::otel::tracing::TraceFlags::SAMPLED
81 } else {
82 wasi::otel::tracing::TraceFlags::empty()
83 }
84 }
85}
86
87impl From<wasi::otel::tracing::SpanKind> for opentelemetry::trace::SpanKind {
88 fn from(kind: wasi::otel::tracing::SpanKind) -> Self {
89 match kind {
90 wasi::otel::tracing::SpanKind::Client => opentelemetry::trace::SpanKind::Client,
91 wasi::otel::tracing::SpanKind::Server => opentelemetry::trace::SpanKind::Server,
92 wasi::otel::tracing::SpanKind::Producer => opentelemetry::trace::SpanKind::Producer,
93 wasi::otel::tracing::SpanKind::Consumer => opentelemetry::trace::SpanKind::Consumer,
94 wasi::otel::tracing::SpanKind::Internal => opentelemetry::trace::SpanKind::Internal,
95 }
96 }
97}
98
99impl From<wasi::otel::tracing::Event> for opentelemetry::trace::Event {
100 fn from(event: wasi::otel::tracing::Event) -> Self {
101 Self::new(
102 event.name,
103 event.time.into(),
104 event.attributes.into_iter().map(Into::into).collect(),
105 0,
106 )
107 }
108}
109
110impl From<wasi::otel::tracing::Link> for opentelemetry::trace::Link {
111 fn from(link: wasi::otel::tracing::Link) -> Self {
112 Self::new(
113 link.span_context.into(),
114 link.attributes.into_iter().map(Into::into).collect(),
115 0,
116 )
117 }
118}
119
120impl From<wasi::otel::tracing::Status> for opentelemetry::trace::Status {
121 fn from(status: wasi::otel::tracing::Status) -> Self {
122 match status {
123 wasi::otel::tracing::Status::Unset => Self::Unset,
124 wasi::otel::tracing::Status::Ok => Self::Ok,
125 wasi::otel::tracing::Status::Error(s) => Self::Error {
126 description: s.into(),
127 },
128 }
129 }
130}
131
132mod test {
133 #[test]
134 fn trace_flags() {
135 let flags = opentelemetry::trace::TraceFlags::SAMPLED;
136 let flags2 = crate::wasi::otel::tracing::TraceFlags::from(flags);
137 let flags3 = opentelemetry::trace::TraceFlags::from(flags2);
138 assert_eq!(flags, flags3);
139 }
140
141 #[test]
142 fn span_context() {
143 let sc = opentelemetry::trace::SpanContext::new(
144 opentelemetry::trace::TraceId::from_hex("4fb34cb4484029f7881399b149e41e98").unwrap(),
145 opentelemetry::trace::SpanId::from_hex("9ffd58d3cd4dd90b").unwrap(),
146 opentelemetry::trace::TraceFlags::SAMPLED,
147 false,
148 opentelemetry::trace::TraceState::from_key_value(vec![("foo", "bar"), ("baz", "qux")])
149 .unwrap(),
150 );
151 let sc2 = crate::wasi::otel::tracing::SpanContext::from(sc.clone());
152 let sc3 = opentelemetry::trace::SpanContext::from(sc2);
153 assert_eq!(sc, sc3);
154 }
155}