diff --git a/cmd/ctr/commands/images/images.go b/cmd/ctr/commands/images/images.go index 05fec7ac0..4ad97d975 100644 --- a/cmd/ctr/commands/images/images.go +++ b/cmd/ctr/commands/images/images.go @@ -17,7 +17,9 @@ package images import ( + "context" "fmt" + "net/http/httptrace" "os" "sort" "strings" @@ -332,3 +334,23 @@ var removeCommand = cli.Command{ return exitErr }, } + +// NewDebugClientTrace returns a Go http trace client predefined to write DNS and connection +// information to the log. This is used via the --trace flag on push and pull operations in ctr. +func NewDebugClientTrace(ctx context.Context) *httptrace.ClientTrace { + return &httptrace.ClientTrace{ + DNSStart: func(dnsInfo httptrace.DNSStartInfo) { + log.G(ctx).WithField("host", dnsInfo.Host).Debugf("DNS lookup") + }, + DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { + if dnsInfo.Err != nil { + log.G(ctx).WithField("lookup_err", dnsInfo.Err).Debugf("DNS lookup error") + } else { + log.G(ctx).WithField("result", dnsInfo.Addrs[0].String()).WithField("coalesced", dnsInfo.Coalesced).Debugf("DNS lookup complete") + } + }, + GotConn: func(connInfo httptrace.GotConnInfo) { + log.G(ctx).WithField("reused", connInfo.Reused).WithField("remote_addr", connInfo.Conn.RemoteAddr().String()).Debugf("Connection successful") + }, + } +} diff --git a/cmd/ctr/commands/images/pull.go b/cmd/ctr/commands/images/pull.go index 93aa63385..495db23cf 100644 --- a/cmd/ctr/commands/images/pull.go +++ b/cmd/ctr/commands/images/pull.go @@ -18,6 +18,7 @@ package images import ( "fmt" + "net/http/httptrace" "github.com/containerd/containerd" "github.com/containerd/containerd/cmd/ctr/commands" @@ -54,6 +55,10 @@ command. As part of this process, we do the following: Name: "all-platforms", Usage: "pull content and metadata from all platforms", }, + cli.BoolFlag{ + Name: "trace", + Usage: "enable HTTP tracing for registry interactions", + }, cli.BoolFlag{ Name: "all-metadata", Usage: "Pull metadata for all platforms", @@ -88,6 +93,9 @@ command. As part of this process, we do the following: return err } + if context.Bool("trace") { + ctx = httptrace.WithClientTrace(ctx, NewDebugClientTrace(ctx)) + } img, err := content.Fetch(ctx, client, ref, config) if err != nil { return err diff --git a/cmd/ctr/commands/images/push.go b/cmd/ctr/commands/images/push.go index 13857235e..fa50082f9 100644 --- a/cmd/ctr/commands/images/push.go +++ b/cmd/ctr/commands/images/push.go @@ -18,6 +18,7 @@ package images import ( gocontext "context" + "net/http/httptrace" "os" "sync" "text/tabwriter" @@ -59,6 +60,9 @@ var pushCommand = cli.Command{ Name: "manifest-type", Usage: "media type of manifest digest", Value: ocispec.MediaTypeImageManifest, + }, cli.BoolFlag{ + Name: "trace", + Usage: "enable HTTP tracing for registry interactions", }, cli.StringSliceFlag{ Name: "platform", Usage: "push content from a specific platform", @@ -119,6 +123,9 @@ var pushCommand = cli.Command{ } } + if context.Bool("trace") { + ctx = httptrace.WithClientTrace(ctx, NewDebugClientTrace(ctx)) + } resolver, err := commands.GetResolver(ctx, context) if err != nil { return err