Docker CLI telemetry accounts for short lived commands
Docker 26.1 adds shared OpenTelemetry support to the CLI. Its resource identity and shutdown exporter address problems that differ from instrumenting a persistent server.
A command-line process can finish before a server-oriented metrics exporter would normally send its first batch. It also starts with a new process identity on every invocation. Treating repeated commands as a single persistent service can leave a telemetry backend waiting for cumulative values that will never arrive. Docker's new CLI telemetry support accounts for both properties in its resource and export code.
The 26.1.0 release notes, dated April 22, describe configurable OpenTelemetry utilities and basic command instrumentation. The underlying change belongs to the Docker CLI. It provides shared tracing and metric facilities that client-side components can use, rather than establishing application instrumentation inside every container.
I value Docker's repeatable build description because it makes execution inputs inspectable. The same preference applies to telemetry configuration. Knowing which process emits a measurement and how its exporter is selected is necessary before using the measurement to explain a slow or failing command.
Common providers replace duplicated setup
PR #4889 explains the motivation for moving OpenTelemetry support into the core CLI. Buildx and Compose had related setup code, and a common implementation lets those projects share subsequent changes. The proposed abstraction remains a thin layer over the OpenTelemetry SDK.
The released telemetry implementation exposes a resource, tracer provider and meter provider through TelemetryClient. Its provider interfaces also expose ForceFlush and Shutdown. Lifecycle operations are therefore explicit parts of the abstraction available to CLI consumers.
Each provider receives the CLI resource and any configured Docker exporter. Callers can supply additional SDK options. This preserves the SDK's configuration model while centralizing the defaults that should agree across commands and plugins.
The resource is initialized lazily and retained for the client instance. Its setup uses sync.Once, so repeated requests do not generate independent default resources within the same client. Callers can also provide a complete resource or append options before initialization. That gives integrations a way to change identity information without reproducing the rest of the provider construction.
Each invocation has an explicit identity
The default resource detects the service name from the executable's basename. It also generates a UUID for the service instance identifier, incorporates resource configuration from the environment, and includes telemetry SDK information. These choices are visible in the version-tagged source rather than being assumptions about generic OpenTelemetry defaults.
The source comment explains the unique instance identifier. Without it, a downstream processor might interpret separate CLI invocations as one process restarting repeatedly. A distinct identity tells the receiver that each invocation is a separate producer.
That is a useful model for a command whose entire useful lifetime may fit inside the aggregation interval of a monitoring system. Reusing a long-running service's identity can imply continuity that the process does not have. Per-invocation identity instead matches the lifetime of the measurements generated during that execution.
The implementation also requests delta temporality for every metric instrument. Its comments acknowledge that unique resources already distinguish invocations, but explain the downstream state benefit. A receiver can aggregate a delta for an interval and discard the corresponding state. Cumulative values can make it retain state in anticipation of another point from the same producer.
Those choices have to be understood together. Unique instance identifiers describe the producers, while delta temporality describes the meaning of their values. Neither setting is a claim that commands are persistent services or that a particular dashboard can aggregate arbitrary metrics correctly without considering their identities.
Shutdown performs the metrics export
The CLI reader wraps an OpenTelemetry manual reader. When its Shutdown method runs, it collects the resource metrics and sends them through the configured exporter. It places a 50 millisecond timeout around that export operation.
The source explains the reason for the short deadline. Telemetry should not prevent the command from exiting if reporting encounters a problem. This creates an explicit preference for bounded reporting time over waiting indefinitely to deliver every measurement.
That timeout is specific to the export operation shown in the reader. It should not be read as a proof that every possible initialization, collection or shutdown path in the process has a total duration of 50 milliseconds. The location of the deadline matters when interpreting what the implementation guarantees.
The CLI entry point creates a meter provider after initialization, registers it with OpenTelemetry, and instruments the Cobra commands. It defers shutdown of that provider. This connects the short-lived process lifecycle to the reader's final collection behavior.
My preference is for this explicit lifecycle in command-line tools. A metrics system designed around a periodic reader needs another way to collect a command that finishes between intervals. Here, the command's return path provides that opportunity, and the export deadline makes the cost visible in the implementation.
The endpoint is selected by Docker configuration
The Docker exporter implementation first reads the current context's metadata. It looks for an otel entry containing OTEL_EXPORTER_OTLP_ENDPOINT. A nonempty DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT environment variable overrides that selection.
For example, a local OTLP gRPC receiver can be selected for one invocation with:
DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 docker version
The code constructs gRPC metric and trace exporters. An endpoint using https selects secure transport, while the other supported cases use the insecure option. It also handles Unix socket URLs separately because stripping their scheme would interfere with the underlying resolver.
When the resolved endpoint is empty, the Docker exporter functions return without adding an exporter. That is the precise behavior established by this code. A wider statement about all Desktop telemetry settings would require examining those settings as well. The PR describes the Docker collection endpoint as active when configured through Desktop.
The result is shared client-side telemetry machinery with a process identity and export lifecycle suited to commands. The current context contributes endpoint configuration, and the invocation supplies the resource lifetime. Those details determine where the measurements originate and when the CLI attempts to deliver them.