From 1f93ab2de4362477d4caac0d000d36fb946c3c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Fri, 4 Sep 2026 17:15:27 +0200 Subject: [PATCH] host: Log loaded extensions and providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Successful host startup did not identify which extensions were initialized or which point providers were admitted, so operators could only infer loading from extension-owned output or behavior. Emit one structured info log per initialized extension after host startup succeeds. Include its ID, origin, admitted provider points, and executable path when applicable. Signed-off-by: Paweł Gronowski --- host/host.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/host/host.go b/host/host.go index f06cd64..295c6b9 100644 --- a/host/host.go +++ b/host/host.go @@ -13,6 +13,7 @@ import ( "slices" "strings" + "github.com/containerd/log" "github.com/moby/extensions" "github.com/moby/extensions/clientpoint" servicev0 "github.com/moby/extensions/extpoints/service/v0" @@ -228,6 +229,11 @@ type loadedExtension struct { close func(context.Context) error } +type registeredExtension struct { + identity extensions.ExtensionIdentity + providers []extensions.Provider +} + // hostedExtension is the runtime-neutral declaration and lifecycle surface // needed to adapt an externally hosted extension to the broker. type hostedExtension struct { @@ -297,6 +303,7 @@ func New(ctx context.Context, optionList ...Option) (_ *Host, retErr error) { b := broker.New() conns := make(map[extensions.ExtensionID]grpc.ClientConnInterface) var loaded []loadedExtension + var registered []registeredExtension publishedServices := make(map[extensions.ExtensionID]map[extensions.PointID][]string) publishedOwners := make(map[string]extensions.ExtensionID) var inProcessServices []servicegrpc.Service @@ -341,6 +348,7 @@ func New(ctx context.Context, optionList ...Option) (_ *Host, retErr error) { if err := b.Register(identity, extensions.New(decl)); err != nil { return nil, err } + registered = append(registered, registeredExtension{identity: identity, providers: admittedProviders}) } l := launcher.Launcher{ RuntimeDir: opts.runtimeDir, @@ -374,6 +382,7 @@ func New(ctx context.Context, optionList ...Option) (_ *Host, retErr error) { if err := b.Register(identity, extensions.New(decl)); err != nil { return nil, err } + registered = append(registered, registeredExtension{identity: identity, providers: admittedProviders}) conns[identity.ID] = started.Conn } } @@ -405,6 +414,21 @@ func New(ctx context.Context, optionList ...Option) (_ *Host, retErr error) { if err := b.Init(ctx, opts.extensionConfig); err != nil { return nil, err } + for _, ext := range registered { + providerIDs := make([]string, len(ext.providers)) + for i, provider := range ext.providers { + providerIDs[i] = string(provider.Point) + } + fields := log.Fields{ + "extension": ext.identity.ID, + "origin": ext.identity.Origin.Kind, + "providers": providerIDs, + } + if executable := ext.identity.Origin.Executable; executable != nil { + fields["path"] = executable.Path + } + log.G(ctx).WithFields(fields).Info("loaded extension") + } return &Host{broker: b, conns: conns, loaded: loaded, publishedServices: publishedServices, inProcessServices: inProcessServices, callback: callback}, nil }