From 31f15b3ed189a1e1cee7eecee14c5cf97fcfbc68 Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Tue, 25 Feb 2025 21:36:10 +0000 Subject: [PATCH 1/3] containerd-shim-wasm/src/sandbox/cli: add logger to the container process this commit initializes the containerd-shim::logger inside of the zygote global process (the container process) so that containers can send logs to contaienrd Signed-off-by: Jiaxiao (mossaka) Zhou --- .../containerd-shim-wasm/src/sandbox/cli.rs | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/crates/containerd-shim-wasm/src/sandbox/cli.rs b/crates/containerd-shim-wasm/src/sandbox/cli.rs index 6690f161b..d502eed7c 100644 --- a/crates/containerd-shim-wasm/src/sandbox/cli.rs +++ b/crates/containerd-shim-wasm/src/sandbox/cli.rs @@ -151,6 +151,22 @@ fn log_mem() { log::info!("Zygote peak memory usage was: peak resident set {rss} kB, peak total {tot} kB"); } +#[cfg(unix)] +fn init_zygote_and_logger(debug: bool, config: &Config) { + zygote::Zygote::init(); + if config.no_setup_logger { + return; + } + zygote::Zygote::global().run( + |(debug, default_log_level)| { + // last two arguments are unused in unix + containerd_shim::logger::init(debug, &default_log_level, "", "") + .expect("Failed to initialize logger"); + }, + (debug, config.default_log_level.clone()), + ); +} + /// Main entry point for the shim. /// /// If the `opentelemetry` feature is enabled, this function will start the shim with OpenTelemetry tracing. @@ -166,8 +182,30 @@ pub fn shim_main<'a, I>( I: 'static + Instance + Sync + Send, I::Engine: Default, { + // parse the version flag + let os_args: Vec<_> = std::env::args_os().collect(); + + let flags = parse(&os_args[1..]).unwrap(); + let argv0 = PathBuf::from(&os_args[0]); + let argv0 = argv0.file_stem().unwrap_or_default().to_string_lossy(); + + if flags.version { + println!("{argv0}:"); + println!(" Runtime: {name}"); + println!(" Version: {version}"); + println!(" Revision: {}", revision.into().unwrap_or("")); + println!(); + + std::process::exit(0); + } + + // Initialize the zygote and logger for the container process #[cfg(unix)] - zygote::Zygote::init(); + { + let default_config = Config::default(); + let config = config.as_ref().unwrap_or(&default_config); + init_zygote_and_logger(flags.debug, config); + } #[cfg(feature = "opentelemetry")] if otel_traces_enabled() { @@ -220,24 +258,8 @@ fn shim_main_inner<'a, I>( } } } - let os_args: Vec<_> = std::env::args_os().collect(); - - let flags = parse(&os_args[1..]).unwrap(); - let argv0 = PathBuf::from(&os_args[0]); - let argv0 = argv0.file_stem().unwrap_or_default().to_string_lossy(); - - if flags.version { - println!("{argv0}:"); - println!(" Runtime: {name}"); - println!(" Version: {version}"); - println!(" Revision: {}", revision.into().unwrap_or("")); - println!(); - - std::process::exit(0); - } let shim_version = shim_version.into().unwrap_or("v1"); - let lower_name = name.to_lowercase(); let shim_id = format!("io.containerd.{lower_name}.{shim_version}"); From a4e42e13f273001f534a9b91e9e5fa8eb2c9ec8c Mon Sep 17 00:00:00 2001 From: "Jiaxiao (mossaka) Zhou" Date: Tue, 25 Feb 2025 22:30:24 +0000 Subject: [PATCH 2/3] feat(all): add container id to runtimeContext so that logs can refer to it This commit adds the container id to the runtimeContext and uses it in the log macros. It does so by adding a new `log` macros that takes a `RuntimeContext` and uses it to log the container id. Signed-off-by: Jiaxiao (mossaka) Zhou --- crates/containerd-shim-wamr/src/instance.rs | 10 +-- .../src/container/context.rs | 19 ++++++ .../containerd-shim-wasm/src/container/log.rs | 68 +++++++++++++++++++ .../containerd-shim-wasm/src/container/mod.rs | 1 + .../src/sys/unix/container/executor.rs | 8 ++- .../src/sys/unix/container/instance.rs | 2 +- .../containerd-shim-wasmedge/src/instance.rs | 4 +- crates/containerd-shim-wasmer/src/instance.rs | 6 +- .../src/http_proxy.rs | 2 +- .../containerd-shim-wasmtime/src/instance.rs | 42 +++++++----- 10 files changed, 132 insertions(+), 30 deletions(-) create mode 100644 crates/containerd-shim-wasm/src/container/log.rs diff --git a/crates/containerd-shim-wamr/src/instance.rs b/crates/containerd-shim-wamr/src/instance.rs index ff021343e..cf3945430 100644 --- a/crates/containerd-shim-wamr/src/instance.rs +++ b/crates/containerd-shim-wamr/src/instance.rs @@ -47,7 +47,7 @@ impl Engine for WamrEngine { .as_bytes() .context("Failed to get bytes from source")?; - log::info!("Create a WAMR module"); + containerd_shim_wasm::info!(ctx, "Create a WAMR module"); // TODO: error handling isn't ideal @@ -56,7 +56,7 @@ impl Engine for WamrEngine { let mut module = Module::from_buf(&self.runtime, &wasm_bytes, &mod_name) .context("Failed to create module from bytes")?; - log::info!("Create a WASI context"); + containerd_shim_wasm::info!(ctx, "Create a WASI context"); let wasi_ctx = WasiCtxBuilder::new() .set_pre_open_path(vec!["/"], vec![]) @@ -68,19 +68,19 @@ impl Engine for WamrEngine { // TODO: no way to register a named module with bytes? - log::info!("Create a WAMR instance"); + containerd_shim_wasm::info!(ctx, "Create a WAMR instance"); let instance = WamrInst::new(&self.runtime, &module, 1024 * 64) .context("Failed to create instance")?; - log::info!("Running {func:?}"); + containerd_shim_wasm::info!(ctx, "Running {func:?}"); let function = Function::find_export_func(&instance, &func).context("Failed to find function")?; let status = function .call(&instance, &vec![]) .map(|_| 0) .map_err(|err| { - log::error!("Error: {:?}", err); + containerd_shim_wasm::error!(ctx, "Error: {:?}", err); err }) .context("Failed to call function")?; diff --git a/crates/containerd-shim-wasm/src/container/context.rs b/crates/containerd-shim-wasm/src/container/context.rs index 9aed9e8cb..f6d905c83 100644 --- a/crates/containerd-shim-wasm/src/container/context.rs +++ b/crates/containerd-shim-wasm/src/container/context.rs @@ -36,6 +36,9 @@ pub trait RuntimeContext { // the platform for the container using the struct defined on the OCI spec definition // https://github.com/opencontainers/image-spec/blob/v1.1.0-rc5/image-index.md fn platform(&self) -> &Platform; + + // the container id for the running container + fn container_id(&self) -> &str; } /// The source for a WASI module / components. @@ -84,6 +87,7 @@ pub(crate) struct WasiContext<'a> { pub spec: &'a Spec, pub wasm_layers: &'a [WasmLayer], pub platform: &'a Platform, + pub id: String, } impl RuntimeContext for WasiContext<'_> { @@ -134,6 +138,10 @@ impl RuntimeContext for WasiContext<'_> { fn platform(&self) -> &Platform { self.platform } + + fn container_id(&self) -> &str { + &self.id + } } #[cfg(test)] @@ -160,6 +168,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let args = ctx.args(); @@ -180,6 +189,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let args = ctx.args(); @@ -208,6 +218,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let args = ctx.args(); @@ -230,6 +241,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let path = ctx.entrypoint().source; @@ -261,6 +273,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let expected_path = PathBuf::from("hello.wat"); @@ -301,6 +314,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let expected_path = PathBuf::from("/root/hello.wat"); @@ -341,6 +355,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let expected_path = PathBuf::from("/root/hello.wat"); @@ -379,6 +394,7 @@ mod tests { ), }], platform: &Platform::default(), + id: "test".to_string(), }; assert!(matches!(ctx.entrypoint().source, Source::Oci(_))); @@ -402,6 +418,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let envs = ctx.envs(); @@ -423,6 +440,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let envs = ctx.envs(); @@ -442,6 +460,7 @@ mod tests { spec: &spec, wasm_layers: &[], platform: &Platform::default(), + id: "test".to_string(), }; let envs = ctx.envs(); diff --git a/crates/containerd-shim-wasm/src/container/log.rs b/crates/containerd-shim-wasm/src/container/log.rs new file mode 100644 index 000000000..c1f6335d4 --- /dev/null +++ b/crates/containerd-shim-wasm/src/container/log.rs @@ -0,0 +1,68 @@ +/// Macros for logging with context information (container ID) automatically included. +#[macro_export] +macro_rules! log_with_ctx { + // Info level log + (info, $ctx:expr, $($arg:tt)+) => { + log::info!(instance = $ctx.container_id(); $($arg)+) + }; + + // Debug level log + (debug, $ctx:expr, $($arg:tt)+) => { + log::debug!(instance = $ctx.container_id(); $($arg)+) + }; + + // Warn level log + (warn, $ctx:expr, $($arg:tt)+) => { + log::warn!(instance = $ctx.container_id(); $($arg)+) + }; + + // Error level log + (error, $ctx:expr, $($arg:tt)+) => { + log::error!(instance = $ctx.container_id(); $($arg)+) + }; + + // Trace level log + (trace, $ctx:expr, $($arg:tt)+) => { + log::trace!(instance = $ctx.container_id(); $($arg)+) + }; +} + +/// Convenience macro for info level logs +#[macro_export] +macro_rules! info { + ($ctx:expr, $($arg:tt)+) => { + $crate::log_with_ctx!(info, $ctx, $($arg)+) + }; +} + +/// Convenience macro for debug level logs +#[macro_export] +macro_rules! debug { + ($ctx:expr, $($arg:tt)+) => { + $crate::log_with_ctx!(debug, $ctx, $($arg)+) + }; +} + +/// Convenience macro for warn level logs +#[macro_export] +macro_rules! warn { + ($ctx:expr, $($arg:tt)+) => { + $crate::log_with_ctx!(warn, $ctx, $($arg)+) + }; +} + +/// Convenience macro for error level logs +#[macro_export] +macro_rules! error { + ($ctx:expr, $($arg:tt)+) => { + $crate::log_with_ctx!(error, $ctx, $($arg)+) + }; +} + +/// Convenience macro for trace level logs +#[macro_export] +macro_rules! trace { + ($ctx:expr, $($arg:tt)+) => { + $crate::log_with_ctx!(trace, $ctx, $($arg)+) + }; +} diff --git a/crates/containerd-shim-wasm/src/container/mod.rs b/crates/containerd-shim-wasm/src/container/mod.rs index 05c445f7a..c4b50e7e8 100644 --- a/crates/containerd-shim-wasm/src/container/mod.rs +++ b/crates/containerd-shim-wasm/src/container/mod.rs @@ -12,6 +12,7 @@ mod context; mod engine; +pub mod log; mod path; mod wasm; diff --git a/crates/containerd-shim-wasm/src/sys/unix/container/executor.rs b/crates/containerd-shim-wasm/src/sys/unix/container/executor.rs index 45f622dde..fece7b191 100644 --- a/crates/containerd-shim-wasm/src/sys/unix/container/executor.rs +++ b/crates/containerd-shim-wasm/src/sys/unix/container/executor.rs @@ -30,6 +30,7 @@ pub(crate) struct Executor { inner: OnceCell, wasm_layers: Vec, platform: Platform, + id: String, } impl LibcontainerExecutor for Executor { @@ -53,8 +54,9 @@ impl LibcontainerExecutor for Executor { DefaultExecutor {}.exec(spec) } InnerExecutor::Wasm => { + let ctx = self.ctx(spec); log::info!("calling start function"); - match self.engine.run_wasi(&self.ctx(spec)) { + match self.engine.run_wasi(&ctx) { Ok(code) => std::process::exit(code), Err(err) => { log::info!("error running start function: {err}"); @@ -82,12 +84,13 @@ impl LibcontainerExecutor for Executor { } impl Executor { - pub fn new(engine: E, wasm_layers: Vec, platform: Platform) -> Self { + pub fn new(engine: E, wasm_layers: Vec, platform: Platform, id: String) -> Self { Self { engine, inner: Default::default(), wasm_layers, platform, + id, } } @@ -98,6 +101,7 @@ impl Executor { spec, wasm_layers, platform, + id: self.id.clone(), } } diff --git a/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs b/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs index c8f5585e4..77ee08fb2 100644 --- a/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs +++ b/crates/containerd-shim-wasm/src/sys/unix/container/instance.rs @@ -55,7 +55,7 @@ impl SandboxInstance for Instance { let engine = E::default(); let mut builder = ContainerBuilder::new(id.clone(), SyscallType::Linux) - .with_executor(Executor::new(engine, modules, platform)) + .with_executor(Executor::new(engine, modules, platform, id)) .with_root_path(rootdir.clone())?; if let Ok(f) = open(cfg.get_stdin()) { diff --git a/crates/containerd-shim-wasmedge/src/instance.rs b/crates/containerd-shim-wasmedge/src/instance.rs index 3c695935d..41dd5c937 100644 --- a/crates/containerd-shim-wasmedge/src/instance.rs +++ b/crates/containerd-shim-wasmedge/src/instance.rs @@ -37,6 +37,8 @@ impl Engine for WasmEdgeEngine { name, } = ctx.entrypoint(); + containerd_shim_wasm::debug!(ctx, "initializing WasmEdge runtime"); + let mut wasi_module = WasiModule::create( Some(args.iter().map(String::as_str).collect()), Some(envs.iter().map(String::as_str).collect()), @@ -54,7 +56,7 @@ impl Engine for WasmEdgeEngine { .register_module(Some(&mod_name), module) .context("registering module")?; - log::debug!("running with method {func:?}"); + containerd_shim_wasm::debug!(ctx, "running with method {func:?}"); vm.run_func(Some(&mod_name), func, vec![])?; Ok(wasi_module.exit_code() as i32) diff --git a/crates/containerd-shim-wasmer/src/instance.rs b/crates/containerd-shim-wasmer/src/instance.rs index abfa83e5f..9600bef4e 100644 --- a/crates/containerd-shim-wasmer/src/instance.rs +++ b/crates/containerd-shim-wasmer/src/instance.rs @@ -36,7 +36,7 @@ impl Engine for WasmerEngine { let mod_name = name.unwrap_or_else(|| "main".to_string()); - log::info!("Create a Store"); + containerd_shim_wasm::info!(ctx, "Create a Store"); let mut store = Store::new(self.engine.clone()); let wasm_bytes = source.as_bytes()?; @@ -47,7 +47,7 @@ impl Engine for WasmerEngine { .build()?; let _guard = runtime.enter(); - log::info!("Creating `WasiEnv`...: args {args:?}, envs: {envs:?}"); + containerd_shim_wasm::info!(ctx, "Creating `WasiEnv`...: args {args:?}, envs: {envs:?}"); let fs = FileSystem::new(Handle::current(), "/")?; let (instance, wasi_env) = WasiEnv::builder(mod_name) .args(&args[1..]) @@ -56,7 +56,7 @@ impl Engine for WasmerEngine { .preopen_dir("/")? .instantiate(module, &mut store)?; - log::info!("Running {func:?}"); + containerd_shim_wasm::info!(ctx, "Running {func:?}"); let start = instance.exports.get_function(&func)?; wasi_env.data(&store).thread.set_status_running(); let status = start.call(&mut store, &[]).map(|_| 0).or_else(|err| { diff --git a/crates/containerd-shim-wasmtime/src/http_proxy.rs b/crates/containerd-shim-wasmtime/src/http_proxy.rs index dd60861ff..04ffc90d1 100644 --- a/crates/containerd-shim-wasmtime/src/http_proxy.rs +++ b/crates/containerd-shim-wasmtime/src/http_proxy.rs @@ -100,7 +100,7 @@ pub(crate) async fn serve_conn( let listener = socket.listen(backlog)?; let tracker = TaskTracker::new(); - log::info!("Serving HTTP on http://{}/", listener.local_addr()?); + containerd_shim_wasm::info!(ctx, "Serving HTTP on http://{}/", listener.local_addr()?); let env = env.into_iter().collect(); let handler = Arc::new(ProxyHandler::new(instance, env, tracker.clone())); diff --git a/crates/containerd-shim-wasmtime/src/instance.rs b/crates/containerd-shim-wasmtime/src/instance.rs index 9cde687dd..0bf2251ea 100644 --- a/crates/containerd-shim-wasmtime/src/instance.rs +++ b/crates/containerd-shim-wasmtime/src/instance.rs @@ -106,6 +106,7 @@ pub struct WasiPreview2Ctx { impl WasiPreview2Ctx { pub fn new(ctx: &impl RuntimeContext) -> Result { + containerd_shim_wasm::debug!(ctx, "Creating new WasiPreview2Ctx"); Ok(Self { wasi_ctx: wasi_builder(ctx)?.build(), wasi_http: WasiHttpCtx::new(), @@ -141,7 +142,7 @@ impl Engine for WasmtimeEngine { } fn run_wasi(&self, ctx: &impl RuntimeContext) -> Result { - log::info!("setting up wasi"); + containerd_shim_wasm::info!(ctx, "setting up wasi"); let Entrypoint { source, func, @@ -202,13 +203,13 @@ impl WasmtimeEngineImpl { module: Module, func: &String, ) -> Result { - log::debug!("execute module"); + containerd_shim_wasm::debug!(ctx, "execute module"); - let ctx = wasi_builder(ctx)?.build_p1(); - let mut store = Store::new(&self.engine, ctx); + let ctx_p1 = wasi_builder(ctx)?.build_p1(); + let mut store = Store::new(&self.engine, ctx_p1); let mut module_linker = wasmtime::Linker::new(&self.engine); - log::debug!("init linker"); + containerd_shim_wasm::debug!(ctx, "init linker"); wasi_preview1::add_to_linker_async(&mut module_linker, |wasi_ctx: &mut WasiP1Ctx| { wasi_ctx })?; @@ -238,7 +239,7 @@ impl WasmtimeEngineImpl { component: Component, func: String, ) -> Result { - log::info!("instantiating component"); + containerd_shim_wasm::info!(ctx, "instantiating component"); let target = ComponentTarget::new( component.component_type().exports(&self.engine), @@ -248,21 +249,21 @@ impl WasmtimeEngineImpl { // This is a adapter logic that converts wasip1 `_start` function to wasip2 `run` function. let status = match target { ComponentTarget::HttpProxy => { - log::info!("Found HTTP proxy target"); + containerd_shim_wasm::info!(ctx, "Found HTTP proxy target"); let mut linker = component::Linker::new(&self.engine); wasmtime_wasi::add_to_linker_async(&mut linker)?; wasmtime_wasi_http::add_only_http_to_linker_async(&mut linker)?; let pre = linker.instantiate_pre(&component)?; - log::info!("pre-instantiate_pre"); + containerd_shim_wasm::info!(ctx, "pre-instantiate_pre"); let instance = ProxyPre::new(pre)?; - log::info!("starting HTTP server"); + containerd_shim_wasm::info!(ctx, "starting HTTP server"); let cancel = self.cancel.clone(); serve_conn(ctx, instance, cancel).await } ComponentTarget::Command => { - log::info!("Found command target"); + containerd_shim_wasm::info!(ctx, "Found command target"); let wasi_ctx = WasiPreview2Ctx::new(ctx)?; let (mut store, linker) = store_for_context(&self.engine, wasi_ctx)?; @@ -279,19 +280,22 @@ impl WasmtimeEngineImpl { }) } ComponentTarget::Core(func) => { - log::info!("Found Core target"); + containerd_shim_wasm::info!(ctx, "Found Core target"); let wasi_ctx = WasiPreview2Ctx::new(ctx)?; let (mut store, linker) = store_for_context(&self.engine, wasi_ctx)?; let pre = linker.instantiate_pre(&component)?; let instance = pre.instantiate_async(&mut store).await?; - log::info!("getting component exported function {func:?}"); + containerd_shim_wasm::info!(ctx, "getting component exported function {func:?}"); let start_func = instance.get_func(&mut store, func).context(format!( "component does not have exported function {func:?}" ))?; - log::debug!("running exported function {func:?} {start_func:?}"); + containerd_shim_wasm::debug!( + ctx, + "running exported function {func:?} {start_func:?}" + ); start_func.call_async(&mut store, &[], &mut []).await } }; @@ -309,7 +313,7 @@ impl WasmtimeEngineImpl { component: Component, func: String, ) -> Result { - log::debug!("loading wasm component"); + containerd_shim_wasm::debug!(ctx, "loading wasm component"); wasmtime_wasi::runtime::in_tokio(async move { tokio::select! { @@ -342,7 +346,7 @@ impl WasmtimeEngineImpl { fn execute(&self, ctx: &impl RuntimeContext, wasm_binary: &[u8], func: String) -> Result { match WasmBinaryType::from_bytes(wasm_binary) { Some(WasmBinaryType::Module) => { - log::debug!("loading wasm module"); + containerd_shim_wasm::debug!(ctx, "loading wasm module"); let module = Module::from_binary(&self.engine, wasm_binary)?; self.execute_module(ctx, module, &func) } @@ -352,12 +356,12 @@ impl WasmtimeEngineImpl { } None => match &self.engine.detect_precompiled(wasm_binary) { Some(Precompiled::Module) => { - log::info!("using precompiled module"); + containerd_shim_wasm::info!(ctx, "using precompiled module"); let module = unsafe { Module::deserialize(&self.engine, wasm_binary) }?; self.execute_module(ctx, module, &func) } Some(Precompiled::Component) => { - log::info!("using precompiled component"); + containerd_shim_wasm::info!(ctx, "using precompiled component"); let component = unsafe { Component::deserialize(&self.engine, wasm_binary) }?; self.execute_component(ctx, component, func) } @@ -396,6 +400,8 @@ fn wasi_builder(ctx: &impl RuntimeContext) -> Result Result Date: Tue, 25 Feb 2025 22:42:16 +0000 Subject: [PATCH 3/3] container: add pod id to the runtimeContext Signed-off-by: Jiaxiao (mossaka) Zhou --- .../src/container/context.rs | 64 ++++++++++++++++++- .../containerd-shim-wasm/src/container/log.rs | 40 ++++++++++-- 2 files changed, 98 insertions(+), 6 deletions(-) diff --git a/crates/containerd-shim-wasm/src/container/context.rs b/crates/containerd-shim-wasm/src/container/context.rs index f6d905c83..364f4cdd8 100644 --- a/crates/containerd-shim-wasm/src/container/context.rs +++ b/crates/containerd-shim-wasm/src/container/context.rs @@ -39,6 +39,13 @@ pub trait RuntimeContext { // the container id for the running container fn container_id(&self) -> &str; + + // the pod id for the running container (if available) + // In Kubernetes environments, containers run within pods, and the pod ID is usually + // stored in the OCI spec annotations under "io.kubernetes.cri.sandbox-id" + fn pod_id(&self) -> Option<&str> { + None + } } /// The source for a WASI module / components. @@ -105,7 +112,7 @@ impl RuntimeContext for WasiContext<'_> { .process() .as_ref() .and_then(|p| p.env().as_ref()) - .map(|e| e.as_slice()) + .map(|a| a.as_slice()) .unwrap_or_default() } @@ -142,6 +149,14 @@ impl RuntimeContext for WasiContext<'_> { fn container_id(&self) -> &str { &self.id } + + fn pod_id(&self) -> Option<&str> { + self.spec + .annotations() + .as_ref() + .and_then(|a| a.get("io.kubernetes.cri.sandbox-id")) + .map(|s| s.as_str()) + } } #[cfg(test)] @@ -468,4 +483,51 @@ mod tests { Ok(()) } + + #[test] + fn test_get_pod_id() -> Result<()> { + use std::collections::HashMap; + + let mut annotations = HashMap::new(); + annotations.insert( + "io.kubernetes.cri.sandbox-id".to_string(), + "test-pod-id".to_string(), + ); + + let spec = SpecBuilder::default() + .root(RootBuilder::default().path("rootfs").build()?) + .process(ProcessBuilder::default().cwd("/").build()?) + .annotations(annotations) + .build()?; + + let ctx = WasiContext { + spec: &spec, + wasm_layers: &[], + platform: &Platform::default(), + id: "test-container".to_string(), + }; + + assert_eq!(ctx.pod_id(), Some("test-pod-id")); + + Ok(()) + } + + #[test] + fn test_get_pod_id_no_annotation() -> Result<()> { + let spec = SpecBuilder::default() + .root(RootBuilder::default().path("rootfs").build()?) + .process(ProcessBuilder::default().cwd("/").build()?) + .build()?; + + let ctx = WasiContext { + spec: &spec, + wasm_layers: &[], + platform: &Platform::default(), + id: "test-container".to_string(), + }; + + assert_eq!(ctx.pod_id(), None); + + Ok(()) + } } diff --git a/crates/containerd-shim-wasm/src/container/log.rs b/crates/containerd-shim-wasm/src/container/log.rs index c1f6335d4..49a3259cd 100644 --- a/crates/containerd-shim-wasm/src/container/log.rs +++ b/crates/containerd-shim-wasm/src/container/log.rs @@ -3,27 +3,57 @@ macro_rules! log_with_ctx { // Info level log (info, $ctx:expr, $($arg:tt)+) => { - log::info!(instance = $ctx.container_id(); $($arg)+) + { + let ctx = $ctx; + match ctx.pod_id() { + Some(pod_id) => log::info!(instance = ctx.container_id(), pod = pod_id; $($arg)+), + None => log::info!(instance = ctx.container_id(); $($arg)+) + } + } }; // Debug level log (debug, $ctx:expr, $($arg:tt)+) => { - log::debug!(instance = $ctx.container_id(); $($arg)+) + { + let ctx = $ctx; + match ctx.pod_id() { + Some(pod_id) => log::debug!(instance = ctx.container_id(), pod = pod_id; $($arg)+), + None => log::debug!(instance = ctx.container_id(); $($arg)+) + } + } }; // Warn level log (warn, $ctx:expr, $($arg:tt)+) => { - log::warn!(instance = $ctx.container_id(); $($arg)+) + { + let ctx = $ctx; + match ctx.pod_id() { + Some(pod_id) => log::warn!(instance = ctx.container_id(), pod = pod_id; $($arg)+), + None => log::warn!(instance = ctx.container_id(); $($arg)+) + } + } }; // Error level log (error, $ctx:expr, $($arg:tt)+) => { - log::error!(instance = $ctx.container_id(); $($arg)+) + { + let ctx = $ctx; + match ctx.pod_id() { + Some(pod_id) => log::error!(instance = ctx.container_id(), pod = pod_id; $($arg)+), + None => log::error!(instance = ctx.container_id(); $($arg)+) + } + } }; // Trace level log (trace, $ctx:expr, $($arg:tt)+) => { - log::trace!(instance = $ctx.container_id(); $($arg)+) + { + let ctx = $ctx; + match ctx.pod_id() { + Some(pod_id) => log::trace!(instance = ctx.container_id(), pod = pod_id; $($arg)+), + None => log::trace!(instance = ctx.container_id(); $($arg)+) + } + } }; }