Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b72abbb6f0 | |||
| 26e9ff49c8 | |||
| 4021ee92fe | |||
| 326c7138bb | |||
| ee359a394b | |||
| 004e2925d7 | |||
| 6691085012 | |||
| 60f2d38d53 | |||
| 81b482ea5e |
@ -52,6 +52,24 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager
|
||||
opts = append(opts, withPluginClientConn(plugin.Name()))
|
||||
}
|
||||
err = tcmd.Initialize(opts...)
|
||||
ogRunE := cmd.RunE
|
||||
if ogRunE == nil {
|
||||
ogRun := cmd.Run
|
||||
// necessary because error will always be nil here
|
||||
// see: https://github.com/golangci/golangci-lint/issues/1379
|
||||
//nolint:unparam
|
||||
ogRunE = func(cmd *cobra.Command, args []string) error {
|
||||
ogRun(cmd, args)
|
||||
return nil
|
||||
}
|
||||
cmd.Run = nil
|
||||
}
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
stopInstrumentation := dockerCli.StartInstrumentation(cmd)
|
||||
err := ogRunE(cmd, args)
|
||||
stopInstrumentation(err)
|
||||
return err
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
@ -273,6 +273,11 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
|
||||
return ResolveDefaultContext(cli.options, cli.contextStoreConfig)
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(krissetto): pass ctx to the funcs instead of using this
|
||||
cli.createGlobalMeterProvider(cli.baseCtx)
|
||||
cli.createGlobalTracerProvider(cli.baseCtx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -41,35 +41,25 @@ type TelemetryClient interface {
|
||||
// each time this function is invoked.
|
||||
Resource() *resource.Resource
|
||||
|
||||
// TracerProvider returns a TracerProvider. This TracerProvider will be configured
|
||||
// with the default tracing components for a CLI program along with any options given
|
||||
// for the SDK.
|
||||
TracerProvider(ctx context.Context, opts ...sdktrace.TracerProviderOption) TracerProvider
|
||||
// TracerProvider returns the currently initialized TracerProvider. This TracerProvider will be configured
|
||||
// with the default tracing components for a CLI program
|
||||
TracerProvider() trace.TracerProvider
|
||||
|
||||
// MeterProvider returns a MeterProvider. This MeterProvider will be configured
|
||||
// with the default metric components for a CLI program along with any options given
|
||||
// for the SDK.
|
||||
MeterProvider(ctx context.Context, opts ...sdkmetric.Option) MeterProvider
|
||||
// MeterProvider returns the currently initialized MeterProvider. This MeterProvider will be configured
|
||||
// with the default metric components for a CLI program
|
||||
MeterProvider() metric.MeterProvider
|
||||
}
|
||||
|
||||
func (cli *DockerCli) Resource() *resource.Resource {
|
||||
return cli.res.Get()
|
||||
}
|
||||
|
||||
func (cli *DockerCli) TracerProvider(ctx context.Context, opts ...sdktrace.TracerProviderOption) TracerProvider {
|
||||
allOpts := make([]sdktrace.TracerProviderOption, 0, len(opts)+2)
|
||||
allOpts = append(allOpts, sdktrace.WithResource(cli.Resource()))
|
||||
allOpts = append(allOpts, dockerSpanExporter(ctx, cli)...)
|
||||
allOpts = append(allOpts, opts...)
|
||||
return sdktrace.NewTracerProvider(allOpts...)
|
||||
func (cli *DockerCli) TracerProvider() trace.TracerProvider {
|
||||
return otel.GetTracerProvider()
|
||||
}
|
||||
|
||||
func (cli *DockerCli) MeterProvider(ctx context.Context, opts ...sdkmetric.Option) MeterProvider {
|
||||
allOpts := make([]sdkmetric.Option, 0, len(opts)+2)
|
||||
allOpts = append(allOpts, sdkmetric.WithResource(cli.Resource()))
|
||||
allOpts = append(allOpts, dockerMetricExporter(ctx, cli)...)
|
||||
allOpts = append(allOpts, opts...)
|
||||
return sdkmetric.NewMeterProvider(allOpts...)
|
||||
func (cli *DockerCli) MeterProvider() metric.MeterProvider {
|
||||
return otel.GetMeterProvider()
|
||||
}
|
||||
|
||||
// WithResourceOptions configures additional options for the default resource. The default
|
||||
@ -122,6 +112,28 @@ func (r *telemetryResource) init() {
|
||||
r.opts = nil
|
||||
}
|
||||
|
||||
// createGlobalMeterProvider creates a new MeterProvider from the initialized DockerCli struct
|
||||
// with the given options and sets it as the global meter provider
|
||||
func (cli *DockerCli) createGlobalMeterProvider(ctx context.Context, opts ...sdkmetric.Option) {
|
||||
allOpts := make([]sdkmetric.Option, 0, len(opts)+2)
|
||||
allOpts = append(allOpts, sdkmetric.WithResource(cli.Resource()))
|
||||
allOpts = append(allOpts, dockerMetricExporter(ctx, cli)...)
|
||||
allOpts = append(allOpts, opts...)
|
||||
mp := sdkmetric.NewMeterProvider(allOpts...)
|
||||
otel.SetMeterProvider(mp)
|
||||
}
|
||||
|
||||
// createGlobalTracerProvider creates a new TracerProvider from the initialized DockerCli struct
|
||||
// with the given options and sets it as the global tracer provider
|
||||
func (cli *DockerCli) createGlobalTracerProvider(ctx context.Context, opts ...sdktrace.TracerProviderOption) {
|
||||
allOpts := make([]sdktrace.TracerProviderOption, 0, len(opts)+2)
|
||||
allOpts = append(allOpts, sdktrace.WithResource(cli.Resource()))
|
||||
allOpts = append(allOpts, dockerSpanExporter(ctx, cli)...)
|
||||
allOpts = append(allOpts, opts...)
|
||||
tp := sdktrace.NewTracerProvider(allOpts...)
|
||||
otel.SetTracerProvider(tp)
|
||||
}
|
||||
|
||||
func defaultResourceOptions() []resource.Option {
|
||||
return []resource.Option{
|
||||
resource.WithDetectors(serviceNameDetector{}),
|
||||
@ -174,11 +186,6 @@ func newCLIReader(exp sdkmetric.Exporter) sdkmetric.Reader {
|
||||
}
|
||||
|
||||
func (r *cliReader) Shutdown(ctx context.Context) error {
|
||||
var rm metricdata.ResourceMetrics
|
||||
if err := r.Reader.Collect(ctx, &rm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Place a pretty tight constraint on the actual reporting.
|
||||
// We don't want CLI metrics to prevent the CLI from exiting
|
||||
// so if there's some kind of issue we need to abort pretty
|
||||
@ -186,6 +193,15 @@ func (r *cliReader) Shutdown(ctx context.Context) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, exportTimeout)
|
||||
defer cancel()
|
||||
|
||||
return r.ForceFlush(ctx)
|
||||
}
|
||||
|
||||
func (r *cliReader) ForceFlush(ctx context.Context) error {
|
||||
var rm metricdata.ResourceMetrics
|
||||
if err := r.Reader.Collect(ctx, &rm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.exporter.Export(ctx, &rm)
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +26,7 @@ func BaseCommandAttributes(cmd *cobra.Command, streams Streams) []attribute.KeyV
|
||||
// Note: this should be the last func to wrap/modify the PersistentRunE/RunE funcs before command execution.
|
||||
//
|
||||
// can also be used for spans!
|
||||
func (cli *DockerCli) InstrumentCobraCommands(cmd *cobra.Command, mp metric.MeterProvider) {
|
||||
meter := getDefaultMeter(mp)
|
||||
func (cli *DockerCli) InstrumentCobraCommands(ctx context.Context, cmd *cobra.Command) {
|
||||
// If PersistentPreRunE is nil, make it execute PersistentPreRun and return nil by default
|
||||
ogPersistentPreRunE := cmd.PersistentPreRunE
|
||||
if ogPersistentPreRunE == nil {
|
||||
@ -55,10 +54,9 @@ func (cli *DockerCli) InstrumentCobraCommands(cmd *cobra.Command, mp metric.Mete
|
||||
}
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
// start the timer as the first step of every cobra command
|
||||
baseAttrs := BaseCommandAttributes(cmd, cli)
|
||||
stopCobraCmdTimer := startCobraCommandTimer(cmd, meter, baseAttrs)
|
||||
stopInstrumentation := cli.StartInstrumentation(cmd)
|
||||
cmdErr := ogRunE(cmd, args)
|
||||
stopCobraCmdTimer(cmdErr)
|
||||
stopInstrumentation(cmdErr)
|
||||
return cmdErr
|
||||
}
|
||||
|
||||
@ -66,8 +64,17 @@ func (cli *DockerCli) InstrumentCobraCommands(cmd *cobra.Command, mp metric.Mete
|
||||
}
|
||||
}
|
||||
|
||||
func startCobraCommandTimer(cmd *cobra.Command, meter metric.Meter, attrs []attribute.KeyValue) func(err error) {
|
||||
ctx := cmd.Context()
|
||||
// StartInstrumentation instruments CLI commands with the individual metrics and spans configured.
|
||||
// It's the main command OTel utility, and new command-related metrics should be added to it.
|
||||
// It should be called immediately before command execution, and returns a stopInstrumentation function
|
||||
// that must be called with the error resulting from the command execution.
|
||||
func (cli *DockerCli) StartInstrumentation(cmd *cobra.Command) (stopInstrumentation func(error)) {
|
||||
baseAttrs := BaseCommandAttributes(cmd, cli)
|
||||
return startCobraCommandTimer(cli.MeterProvider(), baseAttrs)
|
||||
}
|
||||
|
||||
func startCobraCommandTimer(mp metric.MeterProvider, attrs []attribute.KeyValue) func(err error) {
|
||||
meter := getDefaultMeter(mp)
|
||||
durationCounter, _ := meter.Float64Counter(
|
||||
"command.time",
|
||||
metric.WithDescription("Measures the duration of the cobra command"),
|
||||
@ -76,12 +83,20 @@ func startCobraCommandTimer(cmd *cobra.Command, meter metric.Meter, attrs []attr
|
||||
start := time.Now()
|
||||
|
||||
return func(err error) {
|
||||
// Use a new context for the export so that the command being cancelled
|
||||
// doesn't affect the metrics, and we get metrics for cancelled commands.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), exportTimeout)
|
||||
defer cancel()
|
||||
|
||||
duration := float64(time.Since(start)) / float64(time.Millisecond)
|
||||
cmdStatusAttrs := attributesFromError(err)
|
||||
durationCounter.Add(ctx, duration,
|
||||
metric.WithAttributes(attrs...),
|
||||
metric.WithAttributes(cmdStatusAttrs...),
|
||||
)
|
||||
if mp, ok := mp.(MeterProvider); ok {
|
||||
mp.ForceFlush(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -307,10 +307,14 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error {
|
||||
return err
|
||||
}
|
||||
|
||||
mp := dockerCli.MeterProvider(ctx)
|
||||
defer mp.Shutdown(ctx)
|
||||
otel.SetMeterProvider(mp)
|
||||
dockerCli.InstrumentCobraCommands(cmd, mp)
|
||||
mp := dockerCli.MeterProvider()
|
||||
if mp, ok := mp.(command.MeterProvider); ok {
|
||||
defer mp.Shutdown(ctx)
|
||||
} else {
|
||||
fmt.Fprint(dockerCli.Err(), "Warning: Unexpected OTEL error, metrics may not be flushed")
|
||||
}
|
||||
|
||||
dockerCli.InstrumentCobraCommands(ctx, cmd)
|
||||
|
||||
var envs []string
|
||||
args, os.Args, envs, err = processAliases(dockerCli, cmd, args, os.Args)
|
||||
|
||||
@ -117,6 +117,12 @@ data traffic from the management traffic of the cluster.
|
||||
|
||||
If unspecified, the IP address or interface of the advertise address is used.
|
||||
|
||||
Setting `--data-path-addr` does not restrict which interfaces or source IP
|
||||
addresses the VXLAN socket is bound to. Similar to `--advertise-addr`, the
|
||||
purpose of this flag is to inform other members of the swarm about which
|
||||
address to use for control plane traffic. To restrict access to the VXLAN port
|
||||
of the node, use firewall rules.
|
||||
|
||||
### <a name="data-path-port"></a> Configure port number for data traffic (--data-path-port)
|
||||
|
||||
The `--data-path-port` flag allows you to configure the UDP port number to use
|
||||
|
||||
@ -12,7 +12,7 @@ require (
|
||||
github.com/creack/pty v1.1.21
|
||||
github.com/distribution/reference v0.5.0
|
||||
github.com/docker/distribution v2.8.3+incompatible
|
||||
github.com/docker/docker v26.1.2-0.20240508085902-ef1912d8b6ae+incompatible
|
||||
github.com/docker/docker v26.1.3-0.20240515073302-8e96db1c328d+incompatible
|
||||
github.com/docker/docker-credential-helpers v0.8.1
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/docker/go-units v0.5.0
|
||||
|
||||
@ -57,8 +57,8 @@ github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v26.1.2-0.20240508085902-ef1912d8b6ae+incompatible h1:PcRQNw8eAMTjdnD7+y3IeJcsCKqxHmlT0MmqfNs9Jc4=
|
||||
github.com/docker/docker v26.1.2-0.20240508085902-ef1912d8b6ae+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v26.1.3-0.20240515073302-8e96db1c328d+incompatible h1:J+p52tFajMpC0is/1M2mIArncOp4qa+E8hj5Vwt11vs=
|
||||
github.com/docker/docker v26.1.3-0.20240515073302-8e96db1c328d+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
|
||||
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -56,7 +56,7 @@ github.com/docker/distribution/registry/client/transport
|
||||
github.com/docker/distribution/registry/storage/cache
|
||||
github.com/docker/distribution/registry/storage/cache/memory
|
||||
github.com/docker/distribution/uuid
|
||||
# github.com/docker/docker v26.1.2-0.20240508085902-ef1912d8b6ae+incompatible
|
||||
# github.com/docker/docker v26.1.3-0.20240515073302-8e96db1c328d+incompatible
|
||||
## explicit
|
||||
github.com/docker/docker/api
|
||||
github.com/docker/docker/api/types
|
||||
|
||||
Reference in New Issue
Block a user