From 215e8fd5bb12c4f04725ea740add39c2260f17c6 Mon Sep 17 00:00:00 2001 From: Jeremy Clerc Date: Tue, 9 Jun 2026 22:17:13 +0200 Subject: [PATCH 1/2] Add support to write logs to a file This will allow a sidecar to process the logs, either for indexing or any other usecase. --- cmd/main.go | 28 ++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 ++ 3 files changed, 31 insertions(+) diff --git a/cmd/main.go b/cmd/main.go index a6a7ce9..d118d22 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,14 +19,18 @@ package main import ( "flag" "fmt" + "io" "os" "strings" "time" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. + + "go.uber.org/zap/zapcore" _ "k8s.io/client-go/plugin/pkg/client/auth" + "gopkg.in/natefinch/lumberjack.v2" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -63,6 +67,8 @@ func main() { var healthHookTimeout time.Duration var nodeDisruptionTypesRaw string var defaultNodeDisruptionTypesRaw string + var logConsole bool + var logPath string flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, @@ -74,6 +80,8 @@ func main() { flag.DurationVar(&healthHookTimeout, "healthhook-timeout", controller.DefaultHealthHookTimeout, "HTTP client timeout for calling HealthHook resolved from ADB") flag.StringVar(&nodeDisruptionTypesRaw, "node-disruption-types", "", "The list of types allowed for a node disruption separated by a comma.") flag.StringVar(&defaultNodeDisruptionTypesRaw, "default-node-disruption-types", "", "The default list of node disruption types for ADBs that don't specify supportedNodeDisruptionTypes. Must be a subset of --node-disruption-types.") + flag.BoolVar(&logConsole, "log-console", true, "Write logs to the console (stderr)") + flag.StringVar(&logPath, "log-path", "", "Write logs to file at path") opts := zap.Options{ Development: true, @@ -81,6 +89,7 @@ func main() { opts.BindFlags(flag.CommandLine) flag.Parse() + opts.DestWriter = logOutput(logPath, logConsole) ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ @@ -174,3 +183,22 @@ func main() { os.Exit(1) } } + +func logOutput(logPath string, logConsole bool) io.Writer { + if logPath == "" { + return nil // When not set, defaults to console (stderr) anyway. + } + + w := &lumberjack.Logger{ + Filename: logPath, + MaxSize: 10, + MaxBackups: 1, + Compress: false, // disabled by default + } + if logConsole { + return zapcore.NewMultiWriteSyncer( + zapcore.AddSync(w), + zapcore.AddSync(os.Stderr)) + } + return w +} diff --git a/go.mod b/go.mod index af9ee02..5ca6b79 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/gomega v1.36.1 github.com/stretchr/testify v1.11.1 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 k8s.io/api v0.34.2 k8s.io/apimachinery v0.34.2 k8s.io/client-go v0.34.2 diff --git a/go.sum b/go.sum index b3a48cd..2df341d 100644 --- a/go.sum +++ b/go.sum @@ -217,6 +217,8 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnf gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= From ded059330ff119d3704756ad9a23605f32dbb799 Mon Sep 17 00:00:00 2001 From: Jeremy Clerc Date: Wed, 10 Jun 2026 10:13:29 +0200 Subject: [PATCH 2/2] Flags for dynamic configuration of logs rotation --- cmd/main.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index d118d22..d55084d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -69,6 +69,9 @@ func main() { var defaultNodeDisruptionTypesRaw string var logConsole bool var logPath string + var logMaxSize int + var logMaxBackups int + var logCompress bool flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, @@ -82,6 +85,9 @@ func main() { flag.StringVar(&defaultNodeDisruptionTypesRaw, "default-node-disruption-types", "", "The default list of node disruption types for ADBs that don't specify supportedNodeDisruptionTypes. Must be a subset of --node-disruption-types.") flag.BoolVar(&logConsole, "log-console", true, "Write logs to the console (stderr)") flag.StringVar(&logPath, "log-path", "", "Write logs to file at path") + flag.IntVar(&logMaxSize, "log-max-size", 10, "Maximum size of log file when written to disk, in MB") + flag.IntVar(&logMaxBackups, "log-max-backups", 1, "Number of historical log files to keep when written to disk") + flag.BoolVar(&logCompress, "log-compress", false, "Compress rotated logs when written to disk") opts := zap.Options{ Development: true, @@ -89,7 +95,7 @@ func main() { opts.BindFlags(flag.CommandLine) flag.Parse() - opts.DestWriter = logOutput(logPath, logConsole) + opts.DestWriter = logOutput(logConsole, logPath, logMaxSize, logMaxBackups, logCompress) ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ @@ -184,16 +190,16 @@ func main() { } } -func logOutput(logPath string, logConsole bool) io.Writer { +func logOutput(logConsole bool, logPath string, logMaxSize, logMaxBackups int, logCompress bool) io.Writer { if logPath == "" { return nil // When not set, defaults to console (stderr) anyway. } w := &lumberjack.Logger{ Filename: logPath, - MaxSize: 10, - MaxBackups: 1, - Compress: false, // disabled by default + MaxSize: logMaxSize, + MaxBackups: logMaxBackups, + Compress: logCompress, } if logConsole { return zapcore.NewMultiWriteSyncer(