Skip to content

Commit 77f2f0f

Browse files
cpuguy83thaJeztah
authored andcommitted
Add otel tracing support
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1 parent ae83009 commit 77f2f0f

96 files changed

Lines changed: 16480 additions & 6 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cli/command/container/stats.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"github.com/docker/docker/api/types/filters"
2020
"github.com/pkg/errors"
2121
"github.com/spf13/cobra"
22+
"go.opentelemetry.io/otel/attribute"
23+
"go.opentelemetry.io/otel/trace"
2224
)
2325

2426
type statsOptions struct {
@@ -125,13 +127,16 @@ func runStats(ctx context.Context, dockerCli command.Cli, opts *statsOptions) er
125127
}
126128

127129
if showAll {
130+
span := trace.SpanFromContext(ctx)
131+
128132
// If no names were specified, start a long running goroutine which
129133
// monitors container events. We make sure we're subscribed before
130134
// retrieving the list of running containers to avoid a race where we
131135
// would "miss" a creation.
132136
started := make(chan struct{})
133137
eh := command.InitEventHandler()
134138
eh.Handle(events.ActionCreate, func(e events.Message) {
139+
span.AddEvent(string(events.ActionCreate), trace.WithAttributes(attribute.String("ID", e.ID)))
135140
if opts.all {
136141
s := NewStats(e.Actor.ID[:12])
137142
if cStats.add(s) {
@@ -142,6 +147,7 @@ func runStats(ctx context.Context, dockerCli command.Cli, opts *statsOptions) er
142147
})
143148

144149
eh.Handle(events.ActionStart, func(e events.Message) {
150+
span.AddEvent(string(events.ActionStart), trace.WithAttributes(attribute.String("ID", e.Actor.ID)))
145151
s := NewStats(e.Actor.ID[:12])
146152
if cStats.add(s) {
147153
waitFirst.Add(1)
@@ -150,6 +156,7 @@ func runStats(ctx context.Context, dockerCli command.Cli, opts *statsOptions) er
150156
})
151157

152158
eh.Handle(events.ActionDie, func(e events.Message) {
159+
span.AddEvent(string(events.ActionDie), trace.WithAttributes(attribute.String("ID", e.ID)))
153160
if !opts.all {
154161
cStats.remove(e.Actor.ID[:12])
155162
}

cli/command/manifest/rm.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/docker/cli/cli/command"
99
"github.com/pkg/errors"
1010
"github.com/spf13/cobra"
11+
"go.opentelemetry.io/otel/trace"
1112
)
1213

1314
func newRmManifestListCommand(dockerCli command.Cli) *cobra.Command {
@@ -23,11 +24,14 @@ func newRmManifestListCommand(dockerCli command.Cli) *cobra.Command {
2324
return cmd
2425
}
2526

26-
func runRm(_ context.Context, dockerCli command.Cli, targets []string) error {
27+
func runRm(ctx context.Context, dockerCli command.Cli, targets []string) error {
28+
span := trace.SpanFromContext(ctx)
29+
2730
var errs []string
2831
for _, target := range targets {
2932
targetRef, refErr := normalizeReference(target)
3033
if refErr != nil {
34+
span.RecordError(refErr)
3135
errs = append(errs, refErr.Error())
3236
continue
3337
}

cli/command/registry/logout.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/docker/cli/cli/command"
99
"github.com/docker/docker/registry"
1010
"github.com/spf13/cobra"
11+
"go.opentelemetry.io/otel/trace"
1112
)
1213

1314
// NewLogoutCommand creates a new `docker logout` command
@@ -33,7 +34,7 @@ func NewLogoutCommand(dockerCli command.Cli) *cobra.Command {
3334
return cmd
3435
}
3536

36-
func runLogout(_ context.Context, dockerCli command.Cli, serverAddress string) error {
37+
func runLogout(ctx context.Context, dockerCli command.Cli, serverAddress string) error {
3738
var isDefaultRegistry bool
3839

3940
if serverAddress == "" {
@@ -52,10 +53,13 @@ func runLogout(_ context.Context, dockerCli command.Cli, serverAddress string) e
5253
regsToLogout = append(regsToLogout, hostnameAddress, "http://"+hostnameAddress, "https://"+hostnameAddress)
5354
}
5455

56+
span := trace.SpanFromContext(ctx)
57+
5558
fmt.Fprintf(dockerCli.Out(), "Removing login credentials for %s\n", hostnameAddress)
5659
errs := make(map[string]error)
5760
for _, r := range regsToLogout {
5861
if err := dockerCli.ConfigFile().GetCredentialsStore(r).Erase(r); err != nil {
62+
span.RecordError(err)
5963
errs[r] = err
6064
}
6165
}

cmd/docker/docker.go

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"os/exec"
@@ -15,10 +16,14 @@ import (
1516
"github.com/docker/cli/cli/version"
1617
"github.com/docker/cli/cmd/docker/internal/appcontext"
1718
"github.com/docker/docker/api/types/versions"
19+
"github.com/moby/buildkit/util/tracing/detect"
1820
"github.com/pkg/errors"
1921
"github.com/sirupsen/logrus"
2022
"github.com/spf13/cobra"
2123
"github.com/spf13/pflag"
24+
"go.opentelemetry.io/otel"
25+
"go.opentelemetry.io/otel/propagation"
26+
"go.opentelemetry.io/otel/trace"
2227
)
2328

2429
func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
@@ -40,7 +45,25 @@ func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
4045
return fmt.Errorf("docker: '%s' is not a docker command.\nSee 'docker --help'", args[0])
4146
},
4247
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
43-
return isSupported(cmd, dockerCli)
48+
if err := isSupported(cmd, dockerCli); err != nil {
49+
return err
50+
}
51+
52+
name := cmd.Name()
53+
for p := cmd.Parent(); p != nil && p != cmd.Root(); p = p.Parent() {
54+
name = p.Name() + " " + name
55+
}
56+
57+
ctx, _ := otel.Tracer("").Start(cmd.Context(), name)
58+
cmd.SetContext(ctx)
59+
dockerCli.WithContext(ctx)
60+
61+
return nil
62+
},
63+
PersistentPostRun: func(cmd *cobra.Command, args []string) {
64+
// TODO: There doesn't seem to be a way to determine if the command returned an an error
65+
// so we can set the span status here.
66+
trace.SpanFromContext(cmd.Context()).End()
4467
},
4568
Version: fmt.Sprintf("%s, build %s", version.Version, version.GitCommit),
4669
DisableFlagsInUseLine: true,
@@ -54,6 +77,10 @@ func newDockerCommand(dockerCli *command.DockerCli) *cli.TopLevelCommand {
5477
cmd.SetOut(dockerCli.Out())
5578
cmd.SetErr(dockerCli.Err())
5679

80+
// Cobra's context may be nil in some cases, so initialize it here.
81+
ctx := context.TODO()
82+
cmd.SetContext(ctx)
83+
5784
opts, helpCmd = cli.SetupRootCommand(cmd)
5885
registerCompletionFuncForGlobalFlags(dockerCli, cmd)
5986
cmd.Flags().BoolP("version", "v", false, "Print version information and quit")
@@ -227,6 +254,29 @@ func runDocker(dockerCli *command.DockerCli) error {
227254
return err
228255
}
229256

257+
// Buildkit's detect package currently follows the old otel spec which defaulted to gRPC.
258+
// Since the spec changed to default to http/protobuf.
259+
// If these env vars are not set then we set them to the new default so detect will give us the expected protocol.
260+
// This is the same as on the dockerd side.
261+
// This can be removed after buildkit's detect package is updated.
262+
if os.Getenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL") == "" && os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL") == "" {
263+
os.Setenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", "http/protobuf")
264+
}
265+
if v := os.Getenv("OTEL_SERVICE_NAME"); v == "" {
266+
os.Setenv("OTEL_SERVICE_NAME", cmd.Root().Name())
267+
}
268+
269+
tp, err := detect.TracerProvider()
270+
if err != nil {
271+
logrus.WithError(err).Debug("Failed to initialize tracing")
272+
}
273+
274+
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
275+
if tp != nil {
276+
otel.SetTracerProvider(tp)
277+
defer detect.Shutdown(context.Background())
278+
}
279+
230280
var envs []string
231281
args, os.Args, envs, err = processAliases(dockerCli, cmd, args, os.Args)
232282
if err != nil {

vendor.mod

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ require (
3737
github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a
3838
github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d
3939
github.com/xeipuuv/gojsonschema v1.2.0
40+
go.opentelemetry.io/otel v1.14.0
41+
go.opentelemetry.io/otel/trace v1.14.0
4042
golang.org/x/sync v0.3.0
4143
golang.org/x/sys v0.13.0
4244
golang.org/x/term v0.13.0
@@ -51,6 +53,7 @@ require (
5153
github.com/Microsoft/go-winio v0.6.1 // indirect
5254
github.com/Microsoft/hcsshim v0.11.4 // indirect
5355
github.com/beorn7/perks v1.0.1 // indirect
56+
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
5457
github.com/cespare/xxhash/v2 v2.2.0 // indirect
5558
github.com/containerd/log v0.1.0 // indirect
5659
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
@@ -76,9 +79,7 @@ require (
7679
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
7780
go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
7881
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.40.0 // indirect
79-
go.opentelemetry.io/otel v1.14.0 // indirect
8082
go.opentelemetry.io/otel/metric v0.37.0 // indirect
81-
go.opentelemetry.io/otel/trace v1.14.0 // indirect
8283
golang.org/x/crypto v0.14.0 // indirect
8384
golang.org/x/mod v0.11.0 // indirect
8485
golang.org/x/net v0.17.0 // indirect
@@ -88,3 +89,17 @@ require (
8889
google.golang.org/grpc v1.58.3 // indirect
8990
google.golang.org/protobuf v1.31.0 // indirect
9091
)
92+
93+
require github.com/moby/buildkit v0.12.4
94+
95+
require (
96+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
97+
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
98+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
99+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
100+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
101+
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
102+
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
103+
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect
104+
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
105+
)

0 commit comments

Comments
 (0)