Generate trace logs in wiggle albeit behind a feature gate

This commit augments `wiggle` with trace log generation for the shims,
returned errno values, and returned values proper (if any, i.e.,
different than unit type `()`). What that means is that every syscall
will have auto-generated up to 3 traces, for instance,

```
 TRACE wasi_common::wasi::wasi_snapshot_preview1 > fd_prestat_get(fd=Fd(3))
 TRACE wasi_common::wasi::wasi_snapshot_preview1 >      | result=(buf=Dir(PrestatDir { pr_name_len: 1 }))
 TRACE wasi_common::wasi::wasi_snapshot_preview1 >      | errno=No error occurred. System call completed successfully. (Errno::Success(0))
```

Putting logging behind a feature gate in this case means that the log calls
are generated by the `wiggle` crate regardless if the client requested
the feature or not, however, then their usage in the client lib is
dictated by the presence of the feature flag. So, for instance, `wasi-common`
has this feature enabled by default, while any other client lib
using `wiggle` if they don't want tracing enabled, they will just
leave the feature off. I'm not sure if this is what we wanted
but seemed easiest to implement quickly. Lemme y'all know your thoughts
about this!
This commit is contained in:
Jakub Konka
2020-03-28 17:11:32 +01:00
committed by Jakub Konka
parent cd900d72db
commit 78772cf5e1
4 changed files with 82 additions and 231 deletions

View File

@@ -38,9 +38,17 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
};
let err_type = coretype.ret.map(|ret| ret.param.tref);
let err_val = err_type
let ret_err = err_type
.clone()
.map(|_res| quote!(#abi_ret::from(e)))
.map(|_res| {
quote! {
#[cfg(feature = "trace_log")]
{
log::trace!(" | errno={}", e);
}
return #abi_ret::from(e);
}
})
.unwrap_or_else(|| quote!(()));
let error_handling = |location: &str| -> TokenStream {
@@ -78,13 +86,39 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
let (trait_rets, trait_bindings) = if func.results.len() < 2 {
(quote!({}), quote!(_))
} else {
let trait_rets = func
let trait_rets: Vec<_> = func
.results
.iter()
.skip(1)
.map(|result| names.func_param(&result.name));
let tuple = quote!((#(#trait_rets),*));
(tuple.clone(), tuple)
.map(|result| names.func_param(&result.name))
.collect();
let bindings = quote!((#(#trait_rets),*));
let names: Vec<_> = func
.results
.iter()
.skip(1)
.map(|result| {
let name = names.func_param(&result.name);
let fmt = match &*result.tref.type_() {
witx::Type::Builtin(_)
| witx::Type::Enum(_)
| witx::Type::Flags(_)
| witx::Type::Handle(_)
| witx::Type::Int(_) => "{}",
_ => "{:?}",
};
format!("{}={}", name.to_string(), fmt)
})
.collect();
let trace_fmt = format!(" | result=({})", names.join(","));
let rets = quote! {
#[cfg(feature = "trace_log")]
{
log::trace!(#trace_fmt, #(#trait_rets),*);
}
(#(#trait_rets),*)
};
(rets, bindings)
};
// Return value pointers need to be validated before the api call, then
@@ -101,18 +135,40 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
let err_typename = names.type_ref(&err_type, anon_lifetime());
quote! {
let success:#err_typename = wiggle::GuestErrorType::success();
#[cfg(feature = "trace_log")]
{
log::trace!(" | errno={}", success);
}
#abi_ret::from(success)
}
} else {
quote!()
};
let (placeholders, args): (Vec<_>, Vec<_>) = func
.params
.iter()
.map(|param| {
let name = names.func_param(&param.name);
let fmt = if passed_by_reference(&*param.tref.type_()) {
"{:?}"
} else {
"{}"
};
(format!("{}={}", name.to_string(), fmt), quote!(#name))
})
.unzip();
let trace_fmt = format!("{}({})", ident.to_string(), placeholders.join(","));
quote!(pub fn #ident(#abi_args) -> #abi_ret {
#(#marshal_args)*
#(#marshal_rets_pre)*
#[cfg(feature = "trace_log")]
{
log::trace!(#trace_fmt, #(#args),*);
}
let #trait_bindings = match ctx.#ident(#(#trait_args),*) {
Ok(#trait_bindings) => #trait_rets,
Err(e) => { return #err_val; },
Ok(#trait_bindings) => { #trait_rets },
Err(e) => { #ret_err },
};
#(#marshal_rets_post)*
#success