mirror of https://github.com/databricks/cli.git
Recover from panic gracefully (#2353)
## Changes This PR adds a recovery function for panics. This indicates to all users running into a panic that it's a bug and they should report it to Databricks. ## Tests Manually and acceptance test. Before: ``` .venv➜ cli git:(panic-r) ✗ ./cli selftest panic panic: the databricks selftest panic command always panics goroutine 1 [running]: github.com/databricks/cli/cmd/selftest.New.newPanic.func1(0x1400016f208?, {0x1016ca925?, 0x4?, 0x1016ca929?}) /Users/shreyas.goenka/cli2/cli/cmd/selftest/panic.go:9 +0x2c github.com/spf13/cobra.(*Command).execute(0x1400016f208, {0x10279bc40, 0x0, 0x0}) /Users/shreyas.goenka/cli2/cli/vendor/github.com/spf13/cobra/command.go:989 +0x81c github.com/spf13/cobra.(*Command).ExecuteC(0x14000428908) /Users/shreyas.goenka/cli2/cli/vendor/github.com/spf13/cobra/command.go:1117 +0x344 github.com/spf13/cobra.(*Command).ExecuteContextC(...) /Users/shreyas.goenka/cli2/cli/vendor/github.com/spf13/cobra/command.go:1050 github.com/databricks/cli/cmd/root.Execute({0x101d60440?, 0x10279bc40?}, 0x10266dd78?) /Users/shreyas.goenka/cli2/cli/cmd/root/root.go:101 +0x58 main.main() /Users/shreyas.goenka/cli2/cli/main.go:13 +0x44 ``` After: ``` .venv➜ cli git:(panic-r) ./cli selftest panic The Databricks CLI unexpectedly had a fatal error. Please report this issue to Databricks in the form of a GitHub issue at: https://github.com/databricks/cli CLI Version: 0.0.0-dev+aae7ced52d36 Panic Payload: the databricks selftest panic command always panics Stack Trace: goroutine 1 [running]: runtime/debug.Stack() /Users/shreyas.goenka/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/runtime/debug/stack.go:26 +0x64 github.com/databricks/cli/cmd/root.Execute.func1() /Users/shreyas.goenka/cli2/cli/cmd/root/root.go:110 +0xa4 panic({0x10368b5e0?, 0x1039d6d70?}) /Users/shreyas.goenka/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.4.darwin-arm64/src/runtime/panic.go:785 +0x124 github.com/databricks/cli/cmd/selftest.New.newPanic.func1(0x14000145208?, {0x103356be5?, 0x4?, 0x103356be9?}) /Users/shreyas.goenka/cli2/cli/cmd/selftest/panic.go:9 +0x2c github.com/spf13/cobra.(*Command).execute(0x14000145208, {0x104427c40, 0x0, 0x0}) /Users/shreyas.goenka/cli2/cli/vendor/github.com/spf13/cobra/command.go:989 +0x81c github.com/spf13/cobra.(*Command).ExecuteC(0x14000400c08) /Users/shreyas.goenka/cli2/cli/vendor/github.com/spf13/cobra/command.go:1117 +0x344 github.com/spf13/cobra.(*Command).ExecuteContextC(...) /Users/shreyas.goenka/cli2/cli/vendor/github.com/spf13/cobra/command.go:1050 github.com/databricks/cli/cmd/root.Execute({0x1039ec440?, 0x104427c40?}, 0x14000400c08) /Users/shreyas.goenka/cli2/cli/cmd/root/root.go:128 +0x94 main.main() /Users/shreyas.goenka/cli2/cli/main.go:13 +0x44 ```
This commit is contained in:
parent
c1f835f951
commit
bf2aded8e9
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
>>> [CLI] selftest panic
|
||||||
|
The Databricks CLI unexpectedly had a fatal error.
|
||||||
|
Please report this issue to Databricks in the form of a GitHub issue at:
|
||||||
|
https://github.com/databricks/cli
|
||||||
|
|
||||||
|
CLI Version: [DEV_VERSION]
|
||||||
|
|
||||||
|
Panic Payload: the databricks selftest panic command always panics
|
||||||
|
|
||||||
|
Stack Trace:
|
||||||
|
goroutine 1 [running]:
|
||||||
|
runtime/debug.Stack()
|
||||||
|
|
||||||
|
Exit code: 1
|
|
@ -0,0 +1,5 @@
|
||||||
|
# We filter anything after runtime/debug.Stack() in the output because the stack
|
||||||
|
# trace itself is hard to perform replacements on, since it can depend upon the
|
||||||
|
# exact setup of where the modules are installed in your Go setup, memory addresses
|
||||||
|
# at runtime etc.
|
||||||
|
trace $CLI selftest panic 2>&1 | sed '/runtime\/debug\.Stack()/q'
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/databricks/cli/cmd/fs"
|
"github.com/databricks/cli/cmd/fs"
|
||||||
"github.com/databricks/cli/cmd/labs"
|
"github.com/databricks/cli/cmd/labs"
|
||||||
"github.com/databricks/cli/cmd/root"
|
"github.com/databricks/cli/cmd/root"
|
||||||
|
"github.com/databricks/cli/cmd/selftest"
|
||||||
"github.com/databricks/cli/cmd/sync"
|
"github.com/databricks/cli/cmd/sync"
|
||||||
"github.com/databricks/cli/cmd/version"
|
"github.com/databricks/cli/cmd/version"
|
||||||
"github.com/databricks/cli/cmd/workspace"
|
"github.com/databricks/cli/cmd/workspace"
|
||||||
|
@ -74,6 +75,7 @@ func New(ctx context.Context) *cobra.Command {
|
||||||
cli.AddCommand(labs.New(ctx))
|
cli.AddCommand(labs.New(ctx))
|
||||||
cli.AddCommand(sync.New())
|
cli.AddCommand(sync.New())
|
||||||
cli.AddCommand(version.New())
|
cli.AddCommand(version.New())
|
||||||
|
cli.AddCommand(selftest.New())
|
||||||
|
|
||||||
return cli
|
return cli
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/databricks/cli/internal/build"
|
"github.com/databricks/cli/internal/build"
|
||||||
|
@ -96,11 +97,35 @@ func flagErrorFunc(c *cobra.Command, err error) error {
|
||||||
|
|
||||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||||
func Execute(ctx context.Context, cmd *cobra.Command) error {
|
func Execute(ctx context.Context, cmd *cobra.Command) (err error) {
|
||||||
// TODO: deferred panic recovery
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
|
||||||
|
// No panic. Return normally.
|
||||||
|
if r == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := build.GetInfo().Version
|
||||||
|
trace := debug.Stack()
|
||||||
|
|
||||||
|
// Set the error so that the CLI exits with a non-zero exit code.
|
||||||
|
err = fmt.Errorf("panic: %v", r)
|
||||||
|
|
||||||
|
fmt.Fprintf(cmd.ErrOrStderr(), `The Databricks CLI unexpectedly had a fatal error.
|
||||||
|
Please report this issue to Databricks in the form of a GitHub issue at:
|
||||||
|
https://github.com/databricks/cli
|
||||||
|
|
||||||
|
CLI Version: %s
|
||||||
|
|
||||||
|
Panic Payload: %v
|
||||||
|
|
||||||
|
Stack Trace:
|
||||||
|
%s`, version, r, string(trace))
|
||||||
|
}()
|
||||||
|
|
||||||
// Run the command
|
// Run the command
|
||||||
cmd, err := cmd.ExecuteContextC(ctx)
|
cmd, err = cmd.ExecuteContextC(ctx)
|
||||||
if err != nil && !errors.Is(err, ErrAlreadyPrinted) {
|
if err != nil && !errors.Is(err, ErrAlreadyPrinted) {
|
||||||
// If cmdio logger initialization succeeds, then this function logs with the
|
// If cmdio logger initialization succeeds, then this function logs with the
|
||||||
// initialized cmdio logger, otherwise with the default cmdio logger
|
// initialized cmdio logger, otherwise with the default cmdio logger
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package selftest
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
func newPanic() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "panic",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
panic("the databricks selftest panic command always panics")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package selftest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "selftest",
|
||||||
|
Short: "Non functional CLI commands that are useful for testing",
|
||||||
|
Hidden: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.AddCommand(newPanic())
|
||||||
|
return cmd
|
||||||
|
}
|
Loading…
Reference in New Issue