Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ resolver = "2"
members = [
"components/chroot",
"components/readonly",
"components/tracing",
"components/trace",
"crates/test-harness",
]

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A collection of utility components that remix wasi:filesystem types and interfac

- [`chroot`](./components/chroot/)
- [`readonly`](./components/readonly/)
- [`tracing`](./components/tracing/)
- [`trace`](./components/trace/)

## Build

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "tracing"
name = "trace"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
Expand All @@ -11,3 +11,9 @@ crate-type = ["cdylib"]
chrono = { workspace = true }
heck = { workspace = true }
wit-bindgen = { workspace = true }

[dev-dependencies]
tempfile = { workspace = true }
test-harness = { workspace = true }
tokio = { workspace = true }
wasmtime = { workspace = true }
7 changes: 7 additions & 0 deletions components/trace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `trace`

Virtualizes the wasi:filesystem interfaces logging all method calls at the TRACE level and 'filesystem' component.

Each call is logged as `CALL <interface>#<function>` with its arguments, e.g. `CALL wasi:filesystem/types#descriptor.stat-at FD=/dir PATH-FLAGS=(symlink-follow) PATH=sub/file.txt`.

`FD` is the path of the descriptor the call is made on, the directory or file a `PATH` argument is resolved against. A preopen is labeled with its name, e.g. `/`, and a descriptor opened with `open-at` with its physical path: `.` and `..` are applied, and symlinks are followed as the host follows them, every component but the last, and the last with `symlink-follow`. Opening `link/sub` from `/`, where `link` is a symlink to `dir`, is labeled `/dir/sub`. The symlinks are read directly from the host, those calls are not logged. `PATH` arguments are logged as given.
46 changes: 29 additions & 17 deletions components/tracing/src/lib.rs → components/trace/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::fmt::Display;
use std::path::PathBuf;

use chrono::DateTime;
use heck::ToKebabCase;
Expand All @@ -14,6 +13,10 @@ use wasi::filesystem::preopens;
use wasi::filesystem::types;
use wasi::logging::logging::{log, Level};

mod path;

use path::Location;

#[macro_export]
macro_rules! trace {
($dst:expr, $($arg:tt)*) => {
Expand All @@ -35,7 +38,7 @@ impl Preopens for FilesystemTracing {
preopens::get_directories()
.into_iter()
.map(|(fd, path)| {
let fd = Descriptor::new(TracingDescriptor::new(fd, PathBuf::from(path.clone())));
let fd = Descriptor::new(TracingDescriptor::new(fd, Location::preopen(&path)));
(fd, path)
})
.collect()
Expand All @@ -48,12 +51,13 @@ impl Types for FilesystemTracing {

struct TracingDescriptor {
fd: types::Descriptor,
path: PathBuf,
/// What the descriptor is, the base `PATH` arguments are resolved against.
location: Location,
}

impl TracingDescriptor {
fn new(fd: types::Descriptor, path: PathBuf) -> Self {
Self { fd, path }
fn new(fd: types::Descriptor, location: Location) -> Self {
Self { fd, location }
}
}

Expand Down Expand Up @@ -367,13 +371,19 @@ impl exports::wasi::filesystem::types::GuestDescriptor for TracingDescriptor {
) -> Result<Descriptor, ErrorCode> {
trace!("CALL wasi:filesystem/types#descriptor.open-at FD={self} PATH-FLAGS={path_flags} PATH={path} OPEN-FLAGS={open_flags} FLAGS={flags}");

self.fd
let fd = self
.fd
.open_at(path_flags, path.clone(), open_flags, flags)
.await
.map(|fd| {
let path = self.path.clone().join(path);
Descriptor::new(TracingDescriptor::new(fd, path))
.await?;
// the host opened the path, so it is resolved against this descriptor
let follow = path_flags.contains(PathFlags::SYMLINK_FOLLOW);
let location = self
.location
.open(&path, follow, async |path: &str| {
self.fd.readlink_at(path.to_string()).await.ok()
})
.await;
Ok(Descriptor::new(TracingDescriptor::new(fd, location)))
}

#[doc = "/ Read the contents of a symbolic link."]
Expand Down Expand Up @@ -506,18 +516,20 @@ impl exports::wasi::filesystem::types::GuestDescriptor for TracingDescriptor {

impl Display for TracingDescriptor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
&self
.path
.to_str()
.expect("path contains invalid unicode characters"),
)
self.location.fmt(f)
}
}

impl Display for types::Advice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_string().to_kebab_case())
f.write_str(match self {
types::Advice::Normal => "normal",
types::Advice::Sequential => "sequential",
types::Advice::Random => "random",
types::Advice::WillNeed => "will-need",
types::Advice::DontNeed => "dont-need",
types::Advice::NoReuse => "no-reuse",
})
}
}

Expand Down
Loading
Loading