From 9645db767a19329703d4e83de7c7a7b34995a879 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 17 Mar 2026 16:33:00 +0100 Subject: [PATCH 1/2] cli/command/container: RunStats: pass ctx to stats event handlers Wire up the context explicitly instead of capturing it in the closures. Also pass through the context to `watch` to replace the context.TODO() Signed-off-by: Sebastiaan van Stijn --- cli/command/container/stats.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/command/container/stats.go b/cli/command/container/stats.go index 2fad9cc87d72..da37513fb0de 100644 --- a/cli/command/container/stats.go +++ b/cli/command/container/stats.go @@ -145,7 +145,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) eh := newEventHandler() if options.All { - eh.setHandler(events.ActionCreate, func(e events.Message) { + eh.setHandler(events.ActionCreate, func(ctx context.Context, e events.Message) { if s := NewStats(e.Actor.ID); cStats.add(s) { waitFirst.Add(1) log.G(ctx).WithFields(log.Fields{ @@ -157,7 +157,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) }) } - eh.setHandler(events.ActionStart, func(e events.Message) { + eh.setHandler(events.ActionStart, func(ctx context.Context, e events.Message) { if s := NewStats(e.Actor.ID); cStats.add(s) { waitFirst.Add(1) log.G(ctx).WithFields(log.Fields{ @@ -169,7 +169,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) }) if !options.All { - eh.setHandler(events.ActionDie, func(e events.Message) { + eh.setHandler(events.ActionDie, func(ctx context.Context, e events.Message) { log.G(ctx).WithFields(log.Fields{ "event": e.Action, "container": e.Actor.ID, @@ -216,7 +216,7 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) } eventChan := make(chan events.Message) - go eh.watch(eventChan) + go eh.watch(ctx, eventChan) stopped := make(chan struct{}) go monitorContainerEvents(started, eventChan, stopped) defer close(stopped) @@ -369,33 +369,33 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) // newEventHandler initializes and returns an eventHandler func newEventHandler() *eventHandler { - return &eventHandler{handlers: make(map[events.Action]func(events.Message))} + return &eventHandler{handlers: make(map[events.Action]func(context.Context, events.Message))} } // eventHandler allows for registering specific events to setHandler. type eventHandler struct { - handlers map[events.Action]func(events.Message) + handlers map[events.Action]func(context.Context, events.Message) } -func (eh *eventHandler) setHandler(action events.Action, handler func(events.Message)) { +func (eh *eventHandler) setHandler(action events.Action, handler func(context.Context, events.Message)) { eh.handlers[action] = handler } // watch ranges over the passed in event chan and processes the events based on the // handlers created for a given action. // To stop watching, close the event chan. -func (eh *eventHandler) watch(c <-chan events.Message) { +func (eh *eventHandler) watch(ctx context.Context, c <-chan events.Message) { for e := range c { h, exists := eh.handlers[e.Action] if !exists { continue } if e.Actor.ID == "" { - log.G(context.TODO()).WithField("event", e).Errorf("event handler: received %s event with empty ID", e.Action) + log.G(ctx).WithField("event", e).Errorf("event handler: received %s event with empty ID", e.Action) continue } - log.G(context.TODO()).WithField("event", e).Debugf("event handler: received %s event for: %s", e.Action, e.Actor.ID) - go h(e) + log.G(ctx).WithField("event", e).Debugf("event handler: received %s event for: %s", e.Action, e.Actor.ID) + go h(ctx, e) } } From 3f51d0a9d2d494a67ec89e9c52dca01831c7cdcb Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 17 Mar 2026 17:06:19 +0100 Subject: [PATCH 2/2] cli/command/container: RunStats: refactor to DRY - update setHandler to accept multiple event-types - pass a logger to the event-handlers with the common fields already set. Signed-off-by: Sebastiaan van Stijn --- cli/command/container/stats.go | 40 +++++++++++++--------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/cli/command/container/stats.go b/cli/command/container/stats.go index da37513fb0de..9599554fceb0 100644 --- a/cli/command/container/stats.go +++ b/cli/command/container/stats.go @@ -144,36 +144,21 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) } eh := newEventHandler() + addEvents := []events.Action{events.ActionStart} if options.All { - eh.setHandler(events.ActionCreate, func(ctx context.Context, e events.Message) { - if s := NewStats(e.Actor.ID); cStats.add(s) { - waitFirst.Add(1) - log.G(ctx).WithFields(log.Fields{ - "event": e.Action, - "container": e.Actor.ID, - }).Debug("collecting stats for container") - go collect(ctx, s, apiClient, !options.NoStream, waitFirst) - } - }) + addEvents = append(addEvents, events.ActionCreate) } - - eh.setHandler(events.ActionStart, func(ctx context.Context, e events.Message) { + eh.setHandler(addEvents, func(ctx context.Context, e events.Message) { if s := NewStats(e.Actor.ID); cStats.add(s) { waitFirst.Add(1) - log.G(ctx).WithFields(log.Fields{ - "event": e.Action, - "container": e.Actor.ID, - }).Debug("collecting stats for container") + log.G(ctx).Debug("collecting stats for container") go collect(ctx, s, apiClient, !options.NoStream, waitFirst) } }) if !options.All { - eh.setHandler(events.ActionDie, func(ctx context.Context, e events.Message) { - log.G(ctx).WithFields(log.Fields{ - "event": e.Action, - "container": e.Actor.ID, - }).Debug("stop collecting stats for container") + eh.setHandler([]events.Action{events.ActionDie}, func(ctx context.Context, e events.Message) { + log.G(ctx).Debug("stop collecting stats for container") cStats.remove(e.Actor.ID) }) } @@ -377,8 +362,10 @@ type eventHandler struct { handlers map[events.Action]func(context.Context, events.Message) } -func (eh *eventHandler) setHandler(action events.Action, handler func(context.Context, events.Message)) { - eh.handlers[action] = handler +func (eh *eventHandler) setHandler(actions []events.Action, handler func(context.Context, events.Message)) { + for _, action := range actions { + eh.handlers[action] = handler + } } // watch ranges over the passed in event chan and processes the events based on the @@ -394,8 +381,11 @@ func (eh *eventHandler) watch(ctx context.Context, c <-chan events.Message) { log.G(ctx).WithField("event", e).Errorf("event handler: received %s event with empty ID", e.Action) continue } + logger := log.G(ctx).WithFields(log.Fields{ + "event": e.Action, + "container": e.Actor.ID, + }) - log.G(ctx).WithField("event", e).Debugf("event handler: received %s event for: %s", e.Action, e.Actor.ID) - go h(ctx, e) + go h(log.WithLogger(ctx, logger), e) } }