From 97a1929dbcf1db7d97ddd061e32e7c62eb4380f1 Mon Sep 17 00:00:00 2001 From: Austin Vazquez Date: Wed, 1 Jul 2026 10:04:26 -0500 Subject: [PATCH] Add shim log options Signed-off-by: Austin Vazquez --- pkg/logging/logging.go | 45 +++++++++++++++++++++++++++++++++---- pkg/logging/logging_test.go | 17 ++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/pkg/logging/logging.go b/pkg/logging/logging.go index e91f97df..6e501b68 100644 --- a/pkg/logging/logging.go +++ b/pkg/logging/logging.go @@ -31,10 +31,34 @@ import ( "github.com/containerd/log" ) +// SetupShimLogOption configures [SetupShimLog]. +type SetupShimLogOption func(*shimLogConfig) + +type format int + +const ( + formatText format = iota + formatJSON +) + +type shimLogConfig struct { + format format +} + +// WithJSONFormat sets the log output format to emit one JSON object per line. +func WithJSONFormat() SetupShimLogOption { + return func(c *shimLogConfig) { + c.format = formatJSON + } +} + // SetupShimLog configures slog-based logging for the shim process. // It opens the platform-specific log output (FIFO on Unix, named pipe -// on Windows), then creates a slog TextHandler and sets it as the -// default logger with a "component=shim" attribute. +// on Windows), then creates a slog handler and sets it as the default +// logger with a "component=shim" attribute. +// +// The handler's format defaults to text format. Pass [WithJSONFormat] +// to emit JSON, which structured log consumers can unwrap directly. // // The base handler (without component) is stored for use by // [ForwardConsoleLogs] so that forwarded records carry their own @@ -42,7 +66,12 @@ import ( // // For the short-lived start and delete actions, only [log.UseSlog] is // called to route logrus through slog; the log output is not opened. -func SetupShimLog() { +func SetupShimLog(opts ...SetupShimLogOption) { + cfg := shimLogConfig{format: formatText} + for _, o := range opts { + o(&cfg) + } + log.UseSlog() var ( @@ -81,7 +110,15 @@ func SetupShimLog() { log.SetLevel("debug") //nolint:errcheck } - handler := slog.NewTextHandler(w, &slog.HandlerOptions{Level: &level}).WithAttrs(attrs) + handlerOpts := &slog.HandlerOptions{Level: &level} + var handler slog.Handler + switch cfg.format { + case formatJSON: + handler = slog.NewJSONHandler(w, handlerOpts) + default: + handler = slog.NewTextHandler(w, handlerOpts) + } + handler = handler.WithAttrs(attrs) SetBaseHandler(handler) slog.SetDefault(slog.New(handler).With("component", "shim")) } diff --git a/pkg/logging/logging_test.go b/pkg/logging/logging_test.go index 25a5a6a1..9d3e0202 100644 --- a/pkg/logging/logging_test.go +++ b/pkg/logging/logging_test.go @@ -235,6 +235,23 @@ func TestForwardConsoleLogs_DebugLevel(t *testing.T) { } } +func TestWithJSONFormat(t *testing.T) { + cfg := shimLogConfig{format: formatText} + WithJSONFormat()(&cfg) + if cfg.format != formatJSON { + t.Errorf("WithJSONFormat: got %d, want %d", cfg.format, formatJSON) + } +} + +func TestSetupShimLogDefaultIsText(t *testing.T) { + // formatText must be the zero value so that a shimLogConfig without + // explicit initialisation defaults to text (backward-compatible). + var cfg shimLogConfig + if cfg.format != formatText { + t.Errorf("zero-value shimLogConfig.format = %d, want formatText (%d)", cfg.format, formatText) + } +} + func TestForwardJSONLog_InvalidJSON(t *testing.T) { SetBaseHandler(discardHandler{}) if forwardJSONLog("{not json") {