1use alloc::{vec, vec::Vec};
19use codec::{Decode, Encode};
20use core::{fmt::Debug, format_args};
23
24#[derive(Clone, Encode, Decode, Debug)]
26pub enum WasmLevel {
27 ERROR,
29 WARN,
31 INFO,
33 DEBUG,
35 TRACE,
37}
38
39impl From<&tracing_core::Level> for WasmLevel {
40 fn from(l: &tracing_core::Level) -> WasmLevel {
41 match *l {
42 tracing_core::Level::ERROR => WasmLevel::ERROR,
43 tracing_core::Level::WARN => WasmLevel::WARN,
44 tracing_core::Level::INFO => WasmLevel::INFO,
45 tracing_core::Level::DEBUG => WasmLevel::DEBUG,
46 tracing_core::Level::TRACE => WasmLevel::TRACE,
47 }
48 }
49}
50
51impl core::default::Default for WasmLevel {
52 fn default() -> Self {
53 WasmLevel::TRACE
54 }
55}
56
57#[derive(Encode, Decode, Clone)]
59pub enum WasmValue {
60 U8(u8),
61 I8(i8),
62 U32(u32),
63 I32(i32),
64 I64(i64),
65 U64(u64),
66 Bool(bool),
67 Str(Vec<u8>),
68 Formatted(Vec<u8>),
70 Encoded(Vec<u8>),
73}
74
75impl core::fmt::Debug for WasmValue {
76 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
77 match self {
78 WasmValue::U8(ref i) => f.write_fmt(format_args!("{}_u8", i)),
79 WasmValue::I8(ref i) => f.write_fmt(format_args!("{}_i8", i)),
80 WasmValue::U32(ref i) => f.write_fmt(format_args!("{}_u32", i)),
81 WasmValue::I32(ref i) => f.write_fmt(format_args!("{}_i32", i)),
82 WasmValue::I64(ref i) => f.write_fmt(format_args!("{}_i64", i)),
83 WasmValue::U64(ref i) => f.write_fmt(format_args!("{}_u64", i)),
84 WasmValue::Bool(ref i) => f.write_fmt(format_args!("{}_bool", i)),
85 WasmValue::Formatted(ref i) | WasmValue::Str(ref i) => {
86 if let Ok(v) = core::str::from_utf8(i) {
87 f.write_fmt(format_args!("{}", v))
88 } else {
89 f.write_fmt(format_args!("{:?}", i))
90 }
91 },
92 WasmValue::Encoded(ref v) => {
93 f.write_str("Scale(")?;
94 for byte in v {
95 f.write_fmt(format_args!("{:02x}", byte))?;
96 }
97 f.write_str(")")
98 },
99 }
100 }
101}
102
103impl From<u8> for WasmValue {
104 fn from(u: u8) -> WasmValue {
105 WasmValue::U8(u)
106 }
107}
108
109impl From<&i8> for WasmValue {
110 fn from(inp: &i8) -> WasmValue {
111 WasmValue::I8(*inp)
112 }
113}
114
115impl From<&str> for WasmValue {
116 fn from(inp: &str) -> WasmValue {
117 WasmValue::Str(inp.as_bytes().to_vec())
118 }
119}
120
121impl From<&&str> for WasmValue {
122 fn from(inp: &&str) -> WasmValue {
123 WasmValue::Str((*inp).as_bytes().to_vec())
124 }
125}
126
127impl From<bool> for WasmValue {
128 fn from(inp: bool) -> WasmValue {
129 WasmValue::Bool(inp)
130 }
131}
132
133impl From<core::fmt::Arguments<'_>> for WasmValue {
134 fn from(inp: core::fmt::Arguments<'_>) -> WasmValue {
135 let mut buf = alloc::string::String::default();
136 core::fmt::write(&mut buf, inp).expect("Writing of arguments doesn't fail");
137 WasmValue::Formatted(buf.into_bytes())
138 }
139}
140
141impl From<i8> for WasmValue {
142 fn from(u: i8) -> WasmValue {
143 WasmValue::I8(u)
144 }
145}
146
147impl From<i32> for WasmValue {
148 fn from(u: i32) -> WasmValue {
149 WasmValue::I32(u)
150 }
151}
152
153impl From<&i32> for WasmValue {
154 fn from(u: &i32) -> WasmValue {
155 WasmValue::I32(*u)
156 }
157}
158
159impl From<u32> for WasmValue {
160 fn from(u: u32) -> WasmValue {
161 WasmValue::U32(u)
162 }
163}
164
165impl From<&u32> for WasmValue {
166 fn from(u: &u32) -> WasmValue {
167 WasmValue::U32(*u)
168 }
169}
170
171impl From<u64> for WasmValue {
172 fn from(u: u64) -> WasmValue {
173 WasmValue::U64(u)
174 }
175}
176
177impl From<i64> for WasmValue {
178 fn from(u: i64) -> WasmValue {
179 WasmValue::I64(u)
180 }
181}
182
183#[derive(Encode, Decode, Clone)]
188pub struct WasmFieldName(Vec<u8>);
189
190impl core::fmt::Debug for WasmFieldName {
191 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
192 if let Ok(v) = core::str::from_utf8(&self.0) {
193 f.write_fmt(format_args!("{}", v))
194 } else {
195 for byte in self.0.iter() {
196 f.write_fmt(format_args!("{:02x}", byte))?;
197 }
198 Ok(())
199 }
200 }
201}
202
203impl From<Vec<u8>> for WasmFieldName {
204 fn from(v: Vec<u8>) -> Self {
205 WasmFieldName(v)
206 }
207}
208
209impl From<&str> for WasmFieldName {
210 fn from(v: &str) -> Self {
211 WasmFieldName(v.as_bytes().to_vec())
212 }
213}
214
215#[derive(Encode, Decode, Clone, Debug)]
217pub struct WasmFields(Vec<WasmFieldName>);
218
219impl WasmFields {
220 pub fn iter(&self) -> core::slice::Iter<'_, WasmFieldName> {
222 self.0.iter()
223 }
224}
225
226impl From<Vec<WasmFieldName>> for WasmFields {
227 fn from(v: Vec<WasmFieldName>) -> WasmFields {
228 WasmFields(v)
229 }
230}
231
232impl From<Vec<&str>> for WasmFields {
233 fn from(v: Vec<&str>) -> WasmFields {
234 WasmFields(v.into_iter().map(|v| v.into()).collect())
235 }
236}
237
238impl WasmFields {
239 pub fn empty() -> Self {
241 WasmFields(Vec::with_capacity(0))
242 }
243}
244
245impl From<&tracing_core::field::FieldSet> for WasmFields {
246 fn from(wm: &tracing_core::field::FieldSet) -> WasmFields {
247 WasmFields(wm.iter().map(|s| s.name().into()).collect())
248 }
249}
250
251#[derive(Encode, Decode, Clone)]
254pub struct WasmValuesSet(Vec<(WasmFieldName, Option<WasmValue>)>);
255
256impl core::fmt::Debug for WasmValuesSet {
257 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
258 let mut wrt = f.debug_struct("");
259 let mut non_str = false;
260 for (f, v) in self.0.iter() {
261 if let Ok(s) = core::str::from_utf8(&f.0) {
262 match v {
263 Some(ref i) => wrt.field(s, i),
264 None => wrt.field(s, &(None as Option<WasmValue>)),
265 };
266 } else {
267 non_str = true;
268 }
269 }
270
271 if non_str {
274 wrt.field("..", &"..");
275 }
276
277 wrt.finish()
278 }
279}
280
281impl From<Vec<(WasmFieldName, Option<WasmValue>)>> for WasmValuesSet {
282 fn from(v: Vec<(WasmFieldName, Option<WasmValue>)>) -> Self {
283 WasmValuesSet(v)
284 }
285}
286impl From<Vec<(&&WasmFieldName, Option<WasmValue>)>> for WasmValuesSet {
287 fn from(v: Vec<(&&WasmFieldName, Option<WasmValue>)>) -> Self {
288 WasmValuesSet(v.into_iter().map(|(k, v)| ((**k).clone(), v)).collect())
289 }
290}
291
292impl From<Vec<(&&str, Option<WasmValue>)>> for WasmValuesSet {
293 fn from(v: Vec<(&&str, Option<WasmValue>)>) -> Self {
294 WasmValuesSet(v.into_iter().map(|(k, v)| ((*k).into(), v)).collect())
295 }
296}
297
298impl WasmValuesSet {
299 pub fn empty() -> Self {
301 WasmValuesSet(Vec::with_capacity(0))
302 }
303}
304
305impl tracing_core::field::Visit for WasmValuesSet {
306 fn record_debug(&mut self, field: &tracing_core::field::Field, value: &dyn Debug) {
307 self.0
308 .push((field.name().into(), Some(WasmValue::from(format_args!("{:?}", value)))))
309 }
310 fn record_i64(&mut self, field: &tracing_core::field::Field, value: i64) {
311 self.0.push((field.name().into(), Some(WasmValue::from(value))))
312 }
313 fn record_u64(&mut self, field: &tracing_core::field::Field, value: u64) {
314 self.0.push((field.name().into(), Some(WasmValue::from(value))))
315 }
316 fn record_bool(&mut self, field: &tracing_core::field::Field, value: bool) {
317 self.0.push((field.name().into(), Some(WasmValue::from(value))))
318 }
319 fn record_str(&mut self, field: &tracing_core::field::Field, value: &str) {
320 self.0.push((field.name().into(), Some(WasmValue::from(value))))
321 }
322}
323#[derive(Encode, Decode, Clone)]
326pub struct WasmMetadata {
327 pub name: Vec<u8>,
329 pub target: Vec<u8>,
331 pub level: WasmLevel,
333 pub file: Vec<u8>,
335 pub line: u32,
337 pub module_path: Vec<u8>,
339 pub is_span: bool,
341 pub fields: WasmFields,
343}
344
345impl From<&tracing_core::Metadata<'_>> for WasmMetadata {
346 fn from(wm: &tracing_core::Metadata<'_>) -> WasmMetadata {
347 WasmMetadata {
348 name: wm.name().as_bytes().to_vec(),
349 target: wm.target().as_bytes().to_vec(),
350 level: wm.level().into(),
351 file: wm.file().map(|f| f.as_bytes().to_vec()).unwrap_or_default(),
352 line: wm.line().unwrap_or_default(),
353 module_path: wm.module_path().map(|m| m.as_bytes().to_vec()).unwrap_or_default(),
354 is_span: wm.is_span(),
355 fields: wm.fields().into(),
356 }
357 }
358}
359
360impl core::fmt::Debug for WasmMetadata {
361 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
362 f.debug_struct("WasmMetadata")
363 .field("name", &decode_field(&self.name))
364 .field("target", &decode_field(&self.target))
365 .field("level", &self.level)
366 .field("file", &decode_field(&self.file))
367 .field("line", &self.line)
368 .field("module_path", &decode_field(&self.module_path))
369 .field("is_span", &self.is_span)
370 .field("fields", &self.fields)
371 .finish()
372 }
373}
374
375impl core::default::Default for WasmMetadata {
376 fn default() -> Self {
377 let target = "default".as_bytes().to_vec();
378 WasmMetadata {
379 target,
380 name: Default::default(),
381 level: Default::default(),
382 file: Default::default(),
383 line: Default::default(),
384 module_path: Default::default(),
385 is_span: true,
386 fields: WasmFields::empty(),
387 }
388 }
389}
390
391fn decode_field(field: &[u8]) -> &str {
392 core::str::from_utf8(field).unwrap_or_default()
393}
394
395#[derive(Encode, Decode, Clone, Debug)]
397pub struct WasmEntryAttributes {
398 pub parent_id: Option<u64>,
400 pub metadata: WasmMetadata,
402 pub fields: WasmValuesSet,
404}
405
406impl From<&tracing_core::Event<'_>> for WasmEntryAttributes {
407 fn from(evt: &tracing_core::Event<'_>) -> WasmEntryAttributes {
408 let mut fields = WasmValuesSet(Vec::new());
409 evt.record(&mut fields);
410 WasmEntryAttributes {
411 parent_id: evt.parent().map(|id| id.into_u64()),
412 metadata: evt.metadata().into(),
413 fields,
414 }
415 }
416}
417
418impl From<&tracing_core::span::Attributes<'_>> for WasmEntryAttributes {
419 fn from(attrs: &tracing_core::span::Attributes<'_>) -> WasmEntryAttributes {
420 let mut fields = WasmValuesSet(Vec::new());
421 attrs.record(&mut fields);
422 WasmEntryAttributes {
423 parent_id: attrs.parent().map(|id| id.into_u64()),
424 metadata: attrs.metadata().into(),
425 fields,
426 }
427 }
428}
429
430impl core::default::Default for WasmEntryAttributes {
431 fn default() -> Self {
432 WasmEntryAttributes {
433 parent_id: None,
434 metadata: Default::default(),
435 fields: WasmValuesSet(vec![]),
436 }
437 }
438}
439
440#[cfg(feature = "std")]
441mod std_features {
442
443 use tracing_core::callsite;
444
445 pub struct WasmCallsite;
447 impl callsite::Callsite for WasmCallsite {
448 fn set_interest(&self, _: tracing_core::Interest) {
449 unimplemented!()
450 }
451 fn metadata(&self) -> &tracing_core::Metadata {
452 unimplemented!()
453 }
454 }
455 static CALLSITE: WasmCallsite = WasmCallsite;
456 pub static WASM_TRACE_IDENTIFIER: &str = "wasm_tracing";
458 pub static WASM_NAME_KEY: &str = "name";
460 pub static WASM_TARGET_KEY: &str = "target";
462 pub static GENERIC_FIELDS: &[&str] =
464 &[WASM_TARGET_KEY, WASM_NAME_KEY, "file", "line", "module_path", "params"];
465
466 static SPAN_ERROR_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
473 WASM_TRACE_IDENTIFIER,
474 WASM_TRACE_IDENTIFIER,
475 tracing::Level::ERROR,
476 None,
477 None,
478 None,
479 tracing_core::field::FieldSet::new(
480 GENERIC_FIELDS,
481 tracing_core::identify_callsite!(&CALLSITE),
482 ),
483 tracing_core::metadata::Kind::SPAN,
484 );
485
486 static SPAN_WARN_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
487 WASM_TRACE_IDENTIFIER,
488 WASM_TRACE_IDENTIFIER,
489 tracing::Level::WARN,
490 None,
491 None,
492 None,
493 tracing_core::field::FieldSet::new(
494 GENERIC_FIELDS,
495 tracing_core::identify_callsite!(&CALLSITE),
496 ),
497 tracing_core::metadata::Kind::SPAN,
498 );
499 static SPAN_INFO_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
500 WASM_TRACE_IDENTIFIER,
501 WASM_TRACE_IDENTIFIER,
502 tracing::Level::INFO,
503 None,
504 None,
505 None,
506 tracing_core::field::FieldSet::new(
507 GENERIC_FIELDS,
508 tracing_core::identify_callsite!(&CALLSITE),
509 ),
510 tracing_core::metadata::Kind::SPAN,
511 );
512
513 static SPAN_DEBUG_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
514 WASM_TRACE_IDENTIFIER,
515 WASM_TRACE_IDENTIFIER,
516 tracing::Level::DEBUG,
517 None,
518 None,
519 None,
520 tracing_core::field::FieldSet::new(
521 GENERIC_FIELDS,
522 tracing_core::identify_callsite!(&CALLSITE),
523 ),
524 tracing_core::metadata::Kind::SPAN,
525 );
526
527 static SPAN_TRACE_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
528 WASM_TRACE_IDENTIFIER,
529 WASM_TRACE_IDENTIFIER,
530 tracing::Level::TRACE,
531 None,
532 None,
533 None,
534 tracing_core::field::FieldSet::new(
535 GENERIC_FIELDS,
536 tracing_core::identify_callsite!(&CALLSITE),
537 ),
538 tracing_core::metadata::Kind::SPAN,
539 );
540
541 static EVENT_ERROR_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
542 WASM_TRACE_IDENTIFIER,
543 WASM_TRACE_IDENTIFIER,
544 tracing::Level::ERROR,
545 None,
546 None,
547 None,
548 tracing_core::field::FieldSet::new(
549 GENERIC_FIELDS,
550 tracing_core::identify_callsite!(&CALLSITE),
551 ),
552 tracing_core::metadata::Kind::EVENT,
553 );
554
555 static EVENT_WARN_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
556 WASM_TRACE_IDENTIFIER,
557 WASM_TRACE_IDENTIFIER,
558 tracing::Level::WARN,
559 None,
560 None,
561 None,
562 tracing_core::field::FieldSet::new(
563 GENERIC_FIELDS,
564 tracing_core::identify_callsite!(&CALLSITE),
565 ),
566 tracing_core::metadata::Kind::EVENT,
567 );
568
569 static EVENT_INFO_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
570 WASM_TRACE_IDENTIFIER,
571 WASM_TRACE_IDENTIFIER,
572 tracing::Level::INFO,
573 None,
574 None,
575 None,
576 tracing_core::field::FieldSet::new(
577 GENERIC_FIELDS,
578 tracing_core::identify_callsite!(&CALLSITE),
579 ),
580 tracing_core::metadata::Kind::EVENT,
581 );
582
583 static EVENT_DEBUG_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
584 WASM_TRACE_IDENTIFIER,
585 WASM_TRACE_IDENTIFIER,
586 tracing::Level::DEBUG,
587 None,
588 None,
589 None,
590 tracing_core::field::FieldSet::new(
591 GENERIC_FIELDS,
592 tracing_core::identify_callsite!(&CALLSITE),
593 ),
594 tracing_core::metadata::Kind::EVENT,
595 );
596
597 static EVENT_TRACE_METADATA: tracing_core::Metadata<'static> = tracing::Metadata::new(
598 WASM_TRACE_IDENTIFIER,
599 WASM_TRACE_IDENTIFIER,
600 tracing::Level::TRACE,
601 None,
602 None,
603 None,
604 tracing_core::field::FieldSet::new(
605 GENERIC_FIELDS,
606 tracing_core::identify_callsite!(&CALLSITE),
607 ),
608 tracing_core::metadata::Kind::EVENT,
609 );
610
611 impl From<&crate::WasmMetadata> for &'static tracing_core::Metadata<'static> {
614 fn from(wm: &crate::WasmMetadata) -> &'static tracing_core::Metadata<'static> {
615 match (&wm.level, wm.is_span) {
616 (&crate::WasmLevel::ERROR, true) => &SPAN_ERROR_METADATA,
617 (&crate::WasmLevel::WARN, true) => &SPAN_WARN_METADATA,
618 (&crate::WasmLevel::INFO, true) => &SPAN_INFO_METADATA,
619 (&crate::WasmLevel::DEBUG, true) => &SPAN_DEBUG_METADATA,
620 (&crate::WasmLevel::TRACE, true) => &SPAN_TRACE_METADATA,
621 (&crate::WasmLevel::ERROR, false) => &EVENT_ERROR_METADATA,
622 (&crate::WasmLevel::WARN, false) => &EVENT_WARN_METADATA,
623 (&crate::WasmLevel::INFO, false) => &EVENT_INFO_METADATA,
624 (&crate::WasmLevel::DEBUG, false) => &EVENT_DEBUG_METADATA,
625 (&crate::WasmLevel::TRACE, false) => &EVENT_TRACE_METADATA,
626 }
627 }
628 }
629
630 impl From<crate::WasmEntryAttributes> for tracing::Span {
631 fn from(a: crate::WasmEntryAttributes) -> tracing::Span {
632 let name = std::str::from_utf8(&a.metadata.name).unwrap_or_default();
633 let target = std::str::from_utf8(&a.metadata.target).unwrap_or_default();
634 let file = std::str::from_utf8(&a.metadata.file).unwrap_or_default();
635 let line = a.metadata.line;
636 let module_path = std::str::from_utf8(&a.metadata.module_path).unwrap_or_default();
637 let params = a.fields;
638 let metadata: &tracing_core::metadata::Metadata<'static> = (&a.metadata).into();
639
640 tracing::span::Span::child_of(
641 a.parent_id.map(tracing_core::span::Id::from_u64),
642 metadata,
643 &tracing::valueset! { metadata.fields(), target, name, file, line, module_path, ?params },
644 )
645 }
646 }
647
648 impl crate::WasmEntryAttributes {
649 pub fn emit(self: crate::WasmEntryAttributes) {
651 let name = std::str::from_utf8(&self.metadata.name).unwrap_or_default();
652 let target = std::str::from_utf8(&self.metadata.target).unwrap_or_default();
653 let file = std::str::from_utf8(&self.metadata.file).unwrap_or_default();
654 let line = self.metadata.line;
655 let module_path = std::str::from_utf8(&self.metadata.module_path).unwrap_or_default();
656 let params = self.fields;
657 let metadata: &tracing_core::metadata::Metadata<'static> = (&self.metadata).into();
658
659 tracing_core::Event::child_of(
660 self.parent_id.map(tracing_core::span::Id::from_u64),
661 metadata,
662 &tracing::valueset! { metadata.fields(), target, name, file, line, module_path, ?params },
663 )
664 }
665 }
666}
667
668#[cfg(feature = "std")]
669pub use std_features::*;