github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/panic.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/mitchellh/panicwrap"
    10  )
    11  
    12  // This output is shown if a panic happens.
    13  const panicOutput = `
    14  
    15  !!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    16  
    17  Terraform crashed! This is always indicative of a bug within Terraform.
    18  A crash log has been placed at "crash.log" relative to your current
    19  working directory. It would be immensely helpful if you could please
    20  report the crash with Terraform[1] so that we can fix this.
    21  
    22  When reporting bugs, please include your terraform version. That
    23  information is available on the first line of crash.log. You can also
    24  get it by running 'terraform --version' on the command line.
    25  
    26  [1]: https://github.com/hashicorp/terraform/issues
    27  
    28  !!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    29  `
    30  
    31  // panicHandler is what is called by panicwrap when a panic is encountered
    32  // within Terraform. It is guaranteed to run after the resulting process has
    33  // exited so we can take the log file, add in the panic, and store it
    34  // somewhere locally.
    35  func panicHandler(logF *os.File) panicwrap.HandlerFunc {
    36  	return func(m string) {
    37  		// Right away just output this thing on stderr so that it gets
    38  		// shown in case anything below fails.
    39  		fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", m))
    40  
    41  		// Create the crash log file where we'll write the logs
    42  		f, err := os.Create("crash.log")
    43  		if err != nil {
    44  			fmt.Fprintf(os.Stderr, "Failed to create crash log file: %s", err)
    45  			return
    46  		}
    47  		defer f.Close()
    48  
    49  		// Seek the log file back to the beginning
    50  		if _, err = logF.Seek(0, 0); err != nil {
    51  			fmt.Fprintf(os.Stderr, "Failed to seek log file for crash: %s", err)
    52  			return
    53  		}
    54  
    55  		// Copy the contents to the crash file. This will include
    56  		// the panic that just happened.
    57  		if _, err = io.Copy(f, logF); err != nil {
    58  			fmt.Fprintf(os.Stderr, "Failed to write crash log: %s", err)
    59  			return
    60  		}
    61  
    62  		// Tell the user a crash occurred in some helpful way that
    63  		// they'll hopefully notice.
    64  		fmt.Printf("\n\n")
    65  		fmt.Println(strings.TrimSpace(panicOutput))
    66  	}
    67  }