From 196d7d674d97f024cbf5155dae5c0f45f9401878 Mon Sep 17 00:00:00 2001 From: Alex Lyn Date: Fri, 8 Aug 2025 14:15:58 +0800 Subject: [PATCH] runtime-rs: Label system journal log with kata Route kata-shim logs directly to systemd-journald under 'kata' identifier. This refactoring enables `kata-shim` logs to be properly attributed to 'kata' in systemd-journald, instead of inheriting the 'containerd' identifier. Previously, `kata-shim` logs were challenging to filter and debug as they appeared under the `containerd.service` unit. This commit resolves this by: 1. Introducing a `LogDestination` enum to explicitly define logging targets (File or Journal). 2. Modifying logger creation to set `SYSLOG_IDENTIFIER=kata` when logging to Journald. 3. Ensuring type safety and correct ownership handling for different logging backends. This significantly enhances the observability and debuggability of Kata Containers, making it easier to monitor and troubleshoot Kata-specific events. Fixes: #11590 Signed-off-by: Hyounggyu Choi Signed-off-by: Alex Lyn --- src/agent/Cargo.lock | 114 +++++++++++++++++++++-- src/libs/logging/Cargo.toml | 1 + src/libs/logging/src/lib.rs | 79 +++++++++++++--- src/runtime-rs/Cargo.lock | 63 ++++++++++++- src/runtime-rs/crates/shim/src/logger.rs | 25 ++--- 5 files changed, 244 insertions(+), 38 deletions(-) diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock index 14d2b36ea6..c3d86726e7 100644 --- a/src/agent/Cargo.lock +++ b/src/agent/Cargo.lock @@ -508,6 +508,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -889,6 +898,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "darling" version = "0.14.4" @@ -1033,13 +1052,22 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "crypto-common", ] @@ -1543,6 +1571,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + [[package]] name = "home" version = "0.5.9" @@ -2049,7 +2087,7 @@ dependencies = [ "serde", "serde_json", "serial_test", - "sha2", + "sha2 0.10.9", "slog", "slog-scope", "slog-stdlog", @@ -2133,7 +2171,7 @@ dependencies = [ "serde", "serde-enum-str", "serde_json", - "sha2", + "sha2 0.10.9", "slog", "slog-scope", "sysinfo", @@ -2210,6 +2248,23 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a7cbbd4ad467251987c6e5b47d53b11a5a05add08f2447a9e2d70aef1e0d138" +[[package]] +name = "libsystemd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f4f0b5b062ba67aa075e331de778082c09e66b5ef32970ea5a1e9c37c9555d1" +dependencies = [ + "hmac", + "libc", + "log", + "nix 0.23.2", + "once_cell", + "serde", + "sha2 0.9.9", + "thiserror 1.0.69", + "uuid 0.8.2", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -2273,6 +2328,7 @@ dependencies = [ "serde_json", "slog", "slog-async", + "slog-journald", "slog-json", "slog-scope", "slog-term", @@ -2734,6 +2790,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "opentelemetry" version = "0.14.0" @@ -3498,7 +3560,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid", + "uuid 1.16.0", ] [[package]] @@ -3911,7 +3973,20 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", ] [[package]] @@ -3922,7 +3997,7 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -3994,6 +4069,16 @@ dependencies = [ "thread_local", ] +[[package]] +name = "slog-journald" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e14eb8c2f5d0c8fc9fbac40e6391095e4dc5cb334f7dce99c75cb1919eb39c" +dependencies = [ + "libsystemd", + "slog", +] + [[package]] name = "slog-json" version = "2.6.1" @@ -4133,6 +4218,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.109" @@ -4694,6 +4785,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "serde", +] + [[package]] name = "uuid" version = "1.16.0" @@ -4707,7 +4807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" dependencies = [ "outref", - "uuid", + "uuid 1.16.0", "vsimd", ] diff --git a/src/libs/logging/Cargo.toml b/src/libs/logging/Cargo.toml index 033b41712e..aad6712c30 100644 --- a/src/libs/logging/Cargo.toml +++ b/src/libs/logging/Cargo.toml @@ -22,6 +22,7 @@ slog-json = "2.4.0" slog-term = "2.9.1" slog-async = "2.7.0" slog-scope = "4.4.0" +slog-journald = "2.2.0" lazy_static = "1.3.0" arc-swap = "1.5.0" diff --git a/src/libs/logging/src/lib.rs b/src/libs/logging/src/lib.rs index 1d5a8242d3..ec1edcd7bd 100644 --- a/src/libs/logging/src/lib.rs +++ b/src/libs/logging/src/lib.rs @@ -81,6 +81,11 @@ pub fn create_term_logger(level: slog::Level) -> (slog::Logger, slog_async::Asyn (logger, guard) } +pub enum LogDestination { + File(Box), + Journal, +} + // Creates a logger which prints output as JSON // XXX: 'writer' param used to make testing possible. pub fn create_logger( @@ -92,13 +97,43 @@ pub fn create_logger( where W: Write + Send + Sync + 'static, { - let json_drain = slog_json::Json::new(writer) - .add_default_keys() - .build() - .fuse(); + create_logger_with_destination(name, source, level, LogDestination::File(Box::new(writer))) +} + +// Creates a logger which prints output as JSON or to systemd journal +pub fn create_logger_with_destination( + name: &str, + source: &str, + level: slog::Level, + destination: LogDestination, +) -> (slog::Logger, slog_async::AsyncGuard) { + // Check the destination type before consuming it. + // The `matches` macro performs a non-consuming check (it borrows). + let is_journal_destination = matches!(destination, LogDestination::Journal); + + // The target type for boxed drain. Note that Err = slog::Never. + // Both `.fuse()` and `.ignore_res()` convert potential errors into a non-returning path + // (panic or ignore), so they never return an Err. + let drain: Box + Send> = match destination { + LogDestination::File(writer) => { + // `destination` is `File`. + let json_drain = slog_json::Json::new(writer) + .add_default_keys() + .build() + .fuse(); + + Box::new(json_drain) + } + LogDestination::Journal => { + // `destination` is `Journal`. + let journal_drain = slog_journald::JournaldDrain.ignore_res(); + + Box::new(journal_drain) + } + }; // Ensure only a unique set of key/value fields is logged - let unique_drain = UniqueDrain::new(json_drain).fuse(); + let unique_drain = UniqueDrain::new(drain).fuse(); // Adjust the level which will be applied to the log-system // Info is the default level, but if Debug flag is set, the overall log level will be changed to Debug here @@ -119,16 +154,28 @@ where .thread_name("slog-async-logger".into()) .build_with_guard(); - // Add some "standard" fields - let logger = slog::Logger::root( + // Create a base logger with common fields. + let base_logger = slog::Logger::root( async_drain.fuse(), - o!("version" => env!("CARGO_PKG_VERSION"), + o!( + "version" => env!("CARGO_PKG_VERSION"), "subsystem" => DEFAULT_SUBSYSTEM, "pid" => process::id().to_string(), "name" => name.to_string(), - "source" => source.to_string()), + "source" => source.to_string() + ), ); + // If not journal destination, the logger remains the base_logger. + let logger = if is_journal_destination { + // Use the .new() method to build a child logger which inherits all existing + // key-value pairs from its parent and supplements them with additional ones. + // This is the idiomatic way. + base_logger.new(o!("SYSLOG_IDENTIFIER" => "kata")) + } else { + base_logger + }; + (logger, guard) } @@ -502,7 +549,12 @@ mod tests { let record_key = "record-key-1"; let record_value = "record-key-2"; - let (logger, guard) = create_logger(name, source, level, writer); + let (logger, guard) = create_logger_with_destination( + name, + source, + level, + LogDestination::File(Box::new(writer)), + ); let msg = "foo, bar, baz"; @@ -661,7 +713,12 @@ mod tests { .reopen() .unwrap_or_else(|_| panic!("{:?}: failed to clone tempfile", msg)); - let (logger, logger_guard) = create_logger(name, source, d.slog_level, writer); + let (logger, logger_guard) = create_logger_with_destination( + name, + source, + d.slog_level, + LogDestination::File(Box::new(writer)), + ); // Call the logger (which calls the drain) (d.closure)(&logger, d.msg.to_owned()); diff --git a/src/runtime-rs/Cargo.lock b/src/runtime-rs/Cargo.lock index f14ca61754..2a1a05542c 100644 --- a/src/runtime-rs/Cargo.lock +++ b/src/runtime-rs/Cargo.lock @@ -851,6 +851,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "darling" version = "0.14.4" @@ -1787,6 +1797,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + [[package]] name = "hmac" version = "0.12.1" @@ -2304,6 +2324,23 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "libsystemd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f4f0b5b062ba67aa075e331de778082c09e66b5ef32970ea5a1e9c37c9555d1" +dependencies = [ + "hmac 0.11.0", + "libc", + "log", + "nix 0.23.2", + "once_cell", + "serde", + "sha2 0.9.3", + "thiserror 1.0.69", + "uuid 0.8.2", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -2390,6 +2427,7 @@ dependencies = [ "serde_json", "slog", "slog-async", + "slog-journald", "slog-json", "slog-scope", "slog-term", @@ -2797,7 +2835,7 @@ dependencies = [ "bitflags 1.3.2", "fuse-backend-rs", "hex", - "hmac", + "hmac 0.12.1", "httpdate", "lazy_static", "libc", @@ -4464,6 +4502,16 @@ dependencies = [ "thread_local", ] +[[package]] +name = "slog-journald" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e14eb8c2f5d0c8fc9fbac40e6391095e4dc5cb334f7dce99c75cb1919eb39c" +dependencies = [ + "libsystemd", + "slog", +] + [[package]] name = "slog-json" version = "2.6.1" @@ -4617,9 +4665,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" @@ -5195,6 +5243,15 @@ dependencies = [ "rand 0.3.23", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "serde", +] + [[package]] name = "uuid" version = "1.16.0" diff --git a/src/runtime-rs/crates/shim/src/logger.rs b/src/runtime-rs/crates/shim/src/logger.rs index c5d7f225cb..aa7cdfed5c 100644 --- a/src/runtime-rs/crates/shim/src/logger.rs +++ b/src/runtime-rs/crates/shim/src/logger.rs @@ -4,31 +4,22 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::os::unix::fs::OpenOptionsExt; - use anyhow::{Context, Result}; -use crate::Error; - -pub(crate) fn set_logger(path: &str, sid: &str, is_debug: bool) -> Result { - //it's better to open the log pipe file with read & write option, - //otherwise, once the containerd reboot and closed the read endpoint, - //kata shim would write the log pipe with broken pipe error. - let fifo = std::fs::OpenOptions::new() - .custom_flags(libc::O_NONBLOCK) - .create(true) - .read(true) - .write(true) - .open(path) - .context(Error::FileOpen(path.to_string()))?; - +pub(crate) fn set_logger(_path: &str, sid: &str, is_debug: bool) -> Result { let level = if is_debug { slog::Level::Debug } else { slog::Level::Info }; - let (logger, async_guard) = logging::create_logger("kata-runtime", sid, level, fifo); + // Use journal logger to send logs to systemd journal with "kata" identifier + let (logger, async_guard) = logging::create_logger_with_destination( + "kata-runtime", + sid, + level, + logging::LogDestination::Journal, + ); // not reset global logger when drop slog_scope::set_global_logger(logger).cancel_reset();