File: tracing.rs

package info (click to toggle)
rust-wasmtime 26.0.1%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 48,492 kB
  • sloc: ansic: 4,003; sh: 561; javascript: 542; cpp: 254; asm: 175; ml: 96; makefile: 55
file content (130 lines) | stat: -rw-r--r-- 4,589 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use anyhow::Result;
use wiggle::GuestMemory;
use wiggle_test::{impl_errno, HostMemory, WasiCtx};

/// The `errors` argument to the wiggle gives us a hook to map a rich error
/// type like this one (typical of wiggle use cases in wasi-common and beyond)
/// down to the flat error enums that witx can specify.
#[derive(Debug, thiserror::Error)]
pub enum RichError {
    #[error("Invalid argument: {0}")]
    InvalidArg(String),
    #[error("Won't cross picket line: {0}")]
    PicketLine(String),
}

// Define an errno with variants corresponding to RichError. Use it in a
// trivial function.
wiggle::from_witx!({
    tracing: true disable_for {
        one_error_conversion::foo,
    },
witx_literal: "
(typename $errno (enum (@witx tag u8) $ok $invalid_arg $picket_line))
(typename $s (record (field $f1 (@witx usize)) (field $f2 (@witx pointer u8))))
(typename $t (record (field $f1 u32) (field $f2 f32)))
(module $one_error_conversion
  (@interface func (export \"foo\")
     (param $strike u32)
     (param $s $s)
     (result $err (expected $t (error $errno)))))
    ",
    errors: { errno => RichError },
});

impl_errno!(types::Errno);

/// When the `errors` mapping in witx is non-empty, we need to impl the
/// types::UserErrorConversion trait that wiggle generates from that mapping.
impl<'a> types::UserErrorConversion for WasiCtx<'a> {
    fn errno_from_rich_error(&mut self, e: RichError) -> Result<types::Errno> {
        wiggle::tracing::debug!(
            rich_error = wiggle::tracing::field::debug(&e),
            "error conversion"
        );
        // WasiCtx can collect a Vec<String> log so we can test this. We're
        // logging the Display impl that `thiserror::Error` provides us.
        self.log.borrow_mut().push(e.to_string());
        // Then do the trivial mapping down to the flat enum.
        match e {
            RichError::InvalidArg { .. } => Ok(types::Errno::InvalidArg),
            RichError::PicketLine { .. } => Ok(types::Errno::PicketLine),
        }
    }
}

impl<'a> one_error_conversion::OneErrorConversion for WasiCtx<'a> {
    fn foo(
        &mut self,
        _: &mut GuestMemory<'_>,
        strike: u32,
        _s: &types::S,
    ) -> Result<types::T, RichError> {
        // We use the argument to this function to exercise all of the
        // possible error cases we could hit here
        match strike {
            0 => Ok(types::T {
                f1: 123,
                f2: 456.78,
            }),
            1 => Err(RichError::PicketLine(format!("I'm not a scab"))),
            _ => Err(RichError::InvalidArg(format!("out-of-bounds: {strike}"))),
        }
    }
}

fn main() {
    if std::env::var("RUST_LOG").is_err() {
        // with no RUST_LOG env variable: use the tracing subscriber.
        let subscriber = tracing_subscriber::fmt()
            // all spans/events with a level equal to or higher than TRACE (e.g, trace, debug, info, warn, etc.)
            // will be written to stdout.
            .with_max_level(tracing::Level::TRACE)
            // builds the subscriber.
            .finish();
        tracing::subscriber::set_global_default(subscriber).expect("set global tracing subscriber");
    } else {
        // with RUST_LOG set: use the env_logger backend to tracing.
        env_logger::init();
    }

    let mut ctx = WasiCtx::new();
    let mut host_memory = HostMemory::new();
    let mut memory = host_memory.guest_memory();

    // Exercise each of the branches in `foo`.
    // Start with the success case:
    let r0 = one_error_conversion::foo(&mut ctx, &mut memory, 0, 0, 8).unwrap();
    assert_eq!(
        r0,
        types::Errno::Ok as i32,
        "Expected return value for strike=0"
    );
    assert!(ctx.log.borrow().is_empty(), "No error log for strike=0");

    // First error case:
    let r1 = one_error_conversion::foo(&mut ctx, &mut memory, 1, 0, 8).unwrap();
    assert_eq!(
        r1,
        types::Errno::PicketLine as i32,
        "Expected return value for strike=1"
    );
    assert_eq!(
        ctx.log.borrow_mut().pop().expect("one log entry"),
        "Won't cross picket line: I'm not a scab",
        "Expected log entry for strike=1",
    );

    // Second error case:
    let r2 = one_error_conversion::foo(&mut ctx, &mut memory, 2, 0, 8).unwrap();
    assert_eq!(
        r2,
        types::Errno::InvalidArg as i32,
        "Expected return value for strike=2"
    );
    assert_eq!(
        ctx.log.borrow_mut().pop().expect("one log entry"),
        "Invalid argument: out-of-bounds: 2",
        "Expected log entry for strike=2",
    );
}