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 [
46 Value::Enum(level),
47 Value::String(context),
48 Value::String(message),
49 ] = args
50 else {
51 anyhow::bail!("invalid wasi:logging/logging#log arguments");
52 };
53
54 anyhow::ensure!(
55 level.ty() == level_ty,
56 "invalid wasi:logging/logging#log level type"
57 );
58
59 let Some(level) = LOG_LEVELS.get(level.discriminant()) else {
60 anyhow::bail!("invalid wasi:logging/logging#log level kind");
61 };
62
63 log!(target: context, *level, "{message}");
64
65 Ok(())
66 },
67 );
68
69 wasi_logging_instance.define_func("log", log)?;
70
71 Ok(())
72}
73
74#[non_exhaustive]
75pub struct WasiLoggingInterface {
76 pub logging: InterfaceIdentifier,
77}
78
79impl WasiLoggingInterface {
80 #[must_use]
81 pub fn get() -> &'static Self {
82 static WASI_LOGGING_INTERFACE: OnceLock<WasiLoggingInterface> = OnceLock::new();
83
84 WASI_LOGGING_INTERFACE.get_or_init(|| Self {
85 logging: InterfaceIdentifier::new(
86 PackageIdentifier::new(PackageName::new("wasi", "logging"), None),
87 "logging",
88 ),
89 })
90 }
91}