Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions cmd/cmdtrace/cmd_span.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
"io"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -62,7 +63,7 @@ func Setup(cmd *cobra.Command, dockerCli command.Cli, args []string) error {
)

cmd.SetContext(ctx)
wrapRunE(cmd, cmdSpan, tracingShutdown)
wrapRunE(cmd, cmdSpan, tracingShutdown, dockerCli.Err())
return nil
}

Expand All @@ -72,7 +73,7 @@ func Setup(cmd *cobra.Command, dockerCli command.Cli, args []string) error {
//
// Unfortunately, PersistentPostRun(E) can't be used for this purpose because it
// only runs if RunE does _not_ return an error, but this should run unconditionally.
func wrapRunE(c *cobra.Command, cmdSpan trace.Span, tracingShutdown tracing.ShutdownFunc) {
func wrapRunE(c *cobra.Command, cmdSpan trace.Span, tracingShutdown tracing.ShutdownFunc, errOut io.Writer) {
origRunE := c.RunE
if origRunE == nil {
origRun := c.Run
Expand Down Expand Up @@ -110,9 +111,9 @@ func wrapRunE(c *cobra.Command, cmdSpan trace.Span, tracingShutdown tracing.Shut
// been canceled already
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
// TODO(milas): add an env var to enable logging from the
// OTel components for debugging purposes
_ = tracingShutdown(ctx)
if err := tracingShutdown(ctx); err != nil && tracing.DebugEnabled() {
fmt.Fprintln(errOut, "otel: shutdown:", err)
}
}
return cmdErr
}
Expand Down
32 changes: 25 additions & 7 deletions internal/tracing/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,31 @@
package tracing

import (
"fmt"
"os"
"strconv"

"go.opentelemetry.io/otel"
)

// skipErrors is a no-op otel.ErrorHandler.
type skipErrors struct{}

// Handle does nothing, ignoring any errors passed to it.
func (skipErrors) Handle(_ error) {}

var _ otel.ErrorHandler = skipErrors{}
// DebugEnabled reports whether OTel SDK/exporter internals should print
// their diagnostics, controlled by the COMPOSE_OTEL_DEBUG environment
// variable. It defaults to false so tracing plumbing never leaks into
// ordinary CLI output.
func DebugEnabled() bool {
enabled, _ := strconv.ParseBool(os.Getenv("COMPOSE_OTEL_DEBUG"))
return enabled
}

// errorHandler is the otel.ErrorHandler installed for the CLI: it discards
// errors unless DebugEnabled reports true, in which case it prints them to
// stderr.
type errorHandler struct{}

func (errorHandler) Handle(err error) {
if DebugEnabled() {
fmt.Fprintln(os.Stderr, "otel:", err)
}
}

var _ otel.ErrorHandler = errorHandler{}
4 changes: 2 additions & 2 deletions internal/tracing/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import (

func init() {
detect.ServiceName = "compose"
// do not log tracing errors to stdio
otel.SetErrorHandler(skipErrors{})
// do not log tracing errors to stdio, unless COMPOSE_OTEL_DEBUG is set
otel.SetErrorHandler(errorHandler{})
}

// OTLPConfig contains the necessary values to initialize an OTLP client
Expand Down