diff --git a/internal/logging/panic.go b/internal/logging/panic.go index 211a1231d..207b3a444 100644 --- a/internal/logging/panic.go +++ b/internal/logging/panic.go @@ -2,14 +2,12 @@ package logging import ( "fmt" - "io" - "io/ioutil" "os" + "runtime/debug" "strings" "sync" "github.com/hashicorp/go-hclog" - "github.com/mitchellh/panicwrap" ) // This output is shown if a panic happens. @@ -18,59 +16,33 @@ const panicOutput = ` !!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!! Terraform crashed! This is always indicative of a bug within Terraform. -A crash log has been placed at %[1]q relative to your current -working directory. It would be immensely helpful if you could please -report the crash with Terraform[1] so that we can fix this. +Please report the crash with Terraform[1] so that we can fix this. -When reporting bugs, please include your terraform version. That -information is available on the first line of crash.log. You can also -get it by running 'terraform --version' on the command line. - -SECURITY WARNING: the %[1]q file that was created may contain -sensitive information that must be redacted before it is safe to share -on the issue tracker. +When reporting bugs, please include your terraform version, the stack trace +shown below, and any additional information which may help replicate the issue. [1]: https://github.com/hashicorp/terraform/issues !!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!! ` -// panicHandler is what is called by panicwrap when a panic is encountered -// within Terraform. It is guaranteed to run after the resulting process has -// exited so we can take the log file, add in the panic, and store it -// somewhere locally. -func PanicHandler(tmpLogPath string) panicwrap.HandlerFunc { - return func(m string) { - // Create the crash log file where we'll write the logs - f, err := ioutil.TempFile(".", "crash.*.log") - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to create crash log file: %s", err) - return - } - defer f.Close() - - tmpLog, err := os.Open(tmpLogPath) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to open log file %q: %v\n", tmpLogPath, err) - return - } - defer tmpLog.Close() - - // Copy the contents to the crash file. This will include - // the panic that just happened. - if _, err = io.Copy(f, tmpLog); err != nil { - fmt.Fprintf(os.Stderr, "Failed to write crash log: %s", err) - return - } - - // add the trace back to the log - f.WriteString("\n" + m) - - // Tell the user a crash occurred in some helpful way that - // they'll hopefully notice. - fmt.Printf("\n\n") - fmt.Printf(panicOutput, f.Name()) +// PanicHandler is called to recover from an internal panic in Terraform, and +// is intended to replace the standard stack trace with a more user friendly +// error message. +// PanicHandler must be called as a defered function. +func PanicHandler() { + recovered := recover() + if recovered == nil { + return } + + fmt.Fprint(os.Stderr, panicOutput) + fmt.Fprint(os.Stderr, recovered) + + // When called from a deferred function, debug.PrintStack will include the + // full stack from the point of the pending panic. + debug.PrintStack() + os.Exit(2) } const pluginPanicOutput = ` @@ -181,13 +153,5 @@ func (l *logPanicWrapper) Debug(msg string, args ...interface{}) { l.panicRecorder(msg) } - // If we have logging turned on, we need to prevent panicwrap from seeing - // this as a core panic. This can be done by obfuscating the panic error - // line. - if panicPrefix { - colon := strings.Index(msg, ":") - msg = strings.ToUpper(msg[:colon]) + msg[colon:] - } - l.Logger.Debug(msg, args...) } diff --git a/internal/logging/panic_test.go b/internal/logging/panic_test.go index d2eb7a90b..e83a0ba5a 100644 --- a/internal/logging/panic_test.go +++ b/internal/logging/panic_test.go @@ -1,12 +1,9 @@ package logging import ( - "bytes" "fmt" "strings" "testing" - - "github.com/hashicorp/go-hclog" ) func TestPanicRecorder(t *testing.T) { @@ -52,31 +49,3 @@ func TestPanicLimit(t *testing.T) { } } } - -func TestLogPanicWrapper(t *testing.T) { - var buf bytes.Buffer - logger := hclog.NewInterceptLogger(&hclog.LoggerOptions{ - Name: "test", - Level: hclog.Debug, - Output: &buf, - DisableTime: true, - }) - - wrapped := (&logPanicWrapper{ - Logger: logger, - }).Named("test") - - wrapped.Debug("panic: invalid foo of bar") - wrapped.Debug("\tstack trace") - - expected := `[DEBUG] test.test: PANIC: invalid foo of bar -[DEBUG] test.test: stack trace -` - - got := buf.String() - - if expected != got { - t.Fatalf("Expected:\n%q\nGot:\n%q", expected, got) - } - -}