From 39ace450deb23a8ebb4f41ff4d8cfe2800d68118 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 15 Sep 2025 11:29:50 -0400 Subject: [PATCH] logging: Adjustments to BufferedLog to keep logs in the correct order (#7257) * logging: Adjustments to BufferedLog to keep logs in the correct order * Ignore lints --- cmd/commandfuncs.go | 26 ++++++++++++++++++++------ internal/logbuffer.go | 10 ++++++++++ logging.go | 7 +++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go index 9c67e8778..28e33f01b 100644 --- a/cmd/commandfuncs.go +++ b/cmd/commandfuncs.go @@ -182,6 +182,9 @@ func cmdRun(fl Flags) (int, error) { undoMaxProcs := setResourceLimits(logger) defer undoMaxProcs() + // release the local reference to the undo function so it can be GC'd; + // the deferred call above has already captured the actual function value. + undoMaxProcs = nil //nolint:ineffassign,wastedassign configFlag := fl.String("config") configAdapterFlag := fl.String("adapter") @@ -252,12 +255,16 @@ func cmdRun(fl Flags) (int, error) { logBuffer.FlushTo(defaultLogger) return caddy.ExitCodeFailedStartup, fmt.Errorf("loading initial config: %v", err) } + // release the reference to the config so it can be GC'd + config = nil //nolint:ineffassign,wastedassign - // at this stage the config will have replaced - // the default logger to the configured one, so - // we can now flush the buffered logs, then log - // that the config is running. - logBuffer.FlushTo(caddy.Log()) + // at this stage the config will have replaced the + // default logger to the configured one, so we can + // log normally, now that the config is running. + // also clear our ref to the buffer so it can get GC'd + logger = caddy.Log() + defaultLogger = nil //nolint:ineffassign,wastedassign + logBuffer = nil //nolint:wastedassign,ineffassign logger.Info("serving initial configuration") // if we are to report to another process the successful start @@ -273,12 +280,16 @@ func cmdRun(fl Flags) (int, error) { return caddy.ExitCodeFailedStartup, fmt.Errorf("dialing confirmation address: %v", err) } - defer conn.Close() _, err = conn.Write(confirmationBytes) if err != nil { return caddy.ExitCodeFailedStartup, fmt.Errorf("writing confirmation bytes to %s: %v", pingbackFlag, err) } + // close (non-defer because we `select {}` below) + // and release references so they can be GC'd + conn.Close() + confirmationBytes = nil //nolint:ineffassign,wastedassign + conn = nil //nolint:wastedassign,ineffassign } // if enabled, reload config file automatically on changes @@ -306,6 +317,9 @@ func cmdRun(fl Flags) (int, error) { } } + // release the last local logger reference + logger = nil //nolint:wastedassign,ineffassign + select {} } diff --git a/internal/logbuffer.go b/internal/logbuffer.go index 6a3aa7c36..991041bd8 100644 --- a/internal/logbuffer.go +++ b/internal/logbuffer.go @@ -29,6 +29,11 @@ type LogBufferCore struct { level zapcore.LevelEnabler } +type LogBufferCoreInterface interface { + zapcore.Core + FlushTo(*zap.Logger) +} + func NewLogBufferCore(level zapcore.LevelEnabler) *LogBufferCore { return &LogBufferCore{ level: level, @@ -70,3 +75,8 @@ func (c *LogBufferCore) FlushTo(logger *zap.Logger) { c.entries = nil c.fields = nil } + +var ( + _ zapcore.Core = (*LogBufferCore)(nil) + _ LogBufferCoreInterface = (*LogBufferCore)(nil) +) diff --git a/logging.go b/logging.go index fa48fb849..2734b5425 100644 --- a/logging.go +++ b/logging.go @@ -192,6 +192,13 @@ func (logging *Logging) setupNewDefault(ctx Context) error { ) } + // if we had a buffered core, flush its contents ASAP + // before we try to log anything else, so the order of + // logs is preserved + if oldBufferCore, ok := oldDefault.logger.Core().(*internal.LogBufferCore); ok { + oldBufferCore.FlushTo(newDefault.logger) + } + return nil }