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