numcodecs_wasm_host_reproducible/
logging.rs1use std::sync::OnceLock;
2
3use log::Level;
4use wasm_component_layer::{
5 AsContextMut, EnumType, Func, FuncType, InterfaceIdentifier, Linker, PackageIdentifier,
6 PackageName, TypeIdentifier, Value, ValueType,
7};
8
9pub fn add_to_linker(linker: &mut Linker, ctx: impl AsContextMut) -> Result<(), anyhow::Error> {
10 const LEVEL_CASES: [&str; 6] = ["trace", "debug", "info", "warn", "error", "critical"];
11 const LOG_LEVELS: [Level; 6] = [
12 Level::Trace,
13 Level::Debug,
14 Level::Info,
15 Level::Warn,
16 Level::Error,
17 Level::Error,
18 ];
19
20 let WasiLoggingInterface {
21 logging: wasi_logging_interface,
22 } = WasiLoggingInterface::get();
23
24 let wasi_logging_instance = linker.define_instance(wasi_logging_interface.clone())?;
25
26 let level_ty = EnumType::new(
27 Some(TypeIdentifier::new(
28 "level",
29 Some(wasi_logging_interface.clone()),
30 )),
31 LEVEL_CASES,
32 )?;
33
34 let log = Func::new(
35 ctx,
36 FuncType::new(
37 [
38 ValueType::Enum(level_ty.clone()),
39 ValueType::String,
40 ValueType::String,
41 ],
42 [],
43 ),
44 move |_ctx, args, _results| {
45 let [Value::Enum(level), Value::String(context), Value::String(message)] = args else {
46 anyhow::bail!("invalid wasi:logging/logging#log arguments");
47 };
48
49 anyhow::ensure!(
50 level.ty() == level_ty,
51 "invalid wasi:logging/logging#log level type"
52 );
53
54 let Some(level) = LOG_LEVELS.get(level.discriminant()) else {
55 anyhow::bail!("invalid wasi:logging/logging#log level kind");
56 };
57
58 log!(target: context, *level, "{message}");
59
60 Ok(())
61 },
62 );
63
64 wasi_logging_instance.define_func("log", log)?;
65
66 Ok(())
67}
68
69#[non_exhaustive]
70pub struct WasiLoggingInterface {
71 pub logging: InterfaceIdentifier,
72}
73
74impl WasiLoggingInterface {
75 #[must_use]
76 pub fn get() -> &'static Self {
77 static WASI_LOGGING_INTERFACE: OnceLock<WasiLoggingInterface> = OnceLock::new();
78
79 WASI_LOGGING_INTERFACE.get_or_init(|| Self {
80 logging: InterfaceIdentifier::new(
81 PackageIdentifier::new(PackageName::new("wasi", "logging"), None),
82 "logging",
83 ),
84 })
85 }
86}