wrapRunE injects a wrapper function around the command's actual RunE (or Run) method. This is necessary to capture the command result for reporting as well as flushing any spans before exit. Unfortunately, PersistentPostRun(E) can't be used for this purpose because it only runs if RunE does _not_ r
(c *cobra.Command, cmdSpan trace.Span, tracingShutdown tracing.ShutdownFunc)
| 73 | // Unfortunately, PersistentPostRun(E) can't be used for this purpose because it |
| 74 | // only runs if RunE does _not_ return an error, but this should run unconditionally. |
| 75 | func wrapRunE(c *cobra.Command, cmdSpan trace.Span, tracingShutdown tracing.ShutdownFunc) { |
| 76 | origRunE := c.RunE |
| 77 | if origRunE == nil { |
| 78 | origRun := c.Run |
| 79 | //nolint:unparam // wrapper function for RunE, always returns nil by design |
| 80 | origRunE = func(cmd *cobra.Command, args []string) error { |
| 81 | origRun(cmd, args) |
| 82 | return nil |
| 83 | } |
| 84 | c.Run = nil |
| 85 | } |
| 86 | |
| 87 | c.RunE = func(cmd *cobra.Command, args []string) error { |
| 88 | cmdErr := origRunE(cmd, args) |
| 89 | if cmdSpan != nil { |
| 90 | if cmdErr != nil && !errors.Is(cmdErr, context.Canceled) { |
| 91 | // default exit code is 1 if a more descriptive error |
| 92 | // wasn't returned |
| 93 | exitCode := 1 |
| 94 | var statusErr dockercli.StatusError |
| 95 | if errors.As(cmdErr, &statusErr) { |
| 96 | exitCode = statusErr.StatusCode |
| 97 | } |
| 98 | cmdSpan.SetStatus(codes.Error, "CLI command returned error") |
| 99 | cmdSpan.RecordError(cmdErr, trace.WithAttributes( |
| 100 | attribute.Int("exit_code", exitCode), |
| 101 | )) |
| 102 | |
| 103 | } else { |
| 104 | cmdSpan.SetStatus(codes.Ok, "") |
| 105 | } |
| 106 | cmdSpan.End() |
| 107 | } |
| 108 | if tracingShutdown != nil { |
| 109 | // use background for root context because the cmd's context might have |
| 110 | // been canceled already |
| 111 | ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) |
| 112 | defer cancel() |
| 113 | // TODO(milas): add an env var to enable logging from the |
| 114 | // OTel components for debugging purposes |
| 115 | _ = tracingShutdown(ctx) |
| 116 | } |
| 117 | return cmdErr |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | // commandName returns the path components for a given command, |
| 122 | // in reverse alphabetical order for consistent usage metrics. |