102 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Markdown
		
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Markdown
		
	
	
# panicwrap
 | 
						|
 | 
						|
panicwrap is a Go library that re-executes a Go binary and monitors stderr
 | 
						|
output from the binary for a panic. When it find a panic, it executes a
 | 
						|
user-defined handler function. Stdout, stderr, stdin, signals, and exit
 | 
						|
codes continue to work as normal, making the existence of panicwrap mostly
 | 
						|
invisble to the end user until a panic actually occurs.
 | 
						|
 | 
						|
Since a panic is truly a bug in the program meant to crash the runtime,
 | 
						|
globally catching panics within Go applications is not supposed to be possible.
 | 
						|
Despite this, it is often useful to have a way to know when panics occur.
 | 
						|
panicwrap allows you to do something with these panics, such as writing them
 | 
						|
to a file, so that you can track when panics occur.
 | 
						|
 | 
						|
panicwrap is ***not a panic recovery system***. Panics indicate serious
 | 
						|
problems with your application and _should_ crash the runtime. panicwrap
 | 
						|
is just meant as a way to monitor for panics. If you still think this is
 | 
						|
the worst idea ever, read the section below on why.
 | 
						|
 | 
						|
## Features
 | 
						|
 | 
						|
* **SIMPLE!**
 | 
						|
* Works with all Go applications on all platforms Go supports
 | 
						|
* Custom behavior when a panic occurs
 | 
						|
* Stdout, stderr, stdin, exit codes, and signals continue to work as
 | 
						|
  expected.
 | 
						|
 | 
						|
## Usage
 | 
						|
 | 
						|
Using panicwrap is simple. It behaves a lot like `fork`, if you know
 | 
						|
how that works. A basic example is shown below.
 | 
						|
 | 
						|
Because it would be sad to panic while capturing a panic, it is recommended
 | 
						|
that the handler functions for panicwrap remain relatively simple and well
 | 
						|
tested. panicwrap itself contains many tests.
 | 
						|
 | 
						|
```go
 | 
						|
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"github.com/mitchellh/panicwrap"
 | 
						|
	"os"
 | 
						|
)
 | 
						|
 | 
						|
func main() {
 | 
						|
	exitStatus, err := panicwrap.BasicWrap(panicHandler)
 | 
						|
	if err != nil {
 | 
						|
		// Something went wrong setting up the panic wrapper. Unlikely,
 | 
						|
		// but possible.
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
 | 
						|
	// If exitStatus >= 0, then we're the parent process and the panicwrap
 | 
						|
	// re-executed ourselves and completed. Just exit with the proper status.
 | 
						|
	if exitStatus >= 0 {
 | 
						|
		os.Exit(exitStatus)
 | 
						|
	}
 | 
						|
 | 
						|
	// Otherwise, exitStatus < 0 means we're the child. Continue executing as
 | 
						|
	// normal...
 | 
						|
 | 
						|
	// Let's say we panic
 | 
						|
	panic("oh shucks")
 | 
						|
}
 | 
						|
 | 
						|
func panicHandler(output string) {
 | 
						|
	// output contains the full output (including stack traces) of the
 | 
						|
	// panic. Put it in a file or something.
 | 
						|
	fmt.Printf("The child panicked:\n\n%s\n", output)
 | 
						|
	os.Exit(1)
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
## How Does it Work?
 | 
						|
 | 
						|
panicwrap works by re-executing the running program (retaining arguments,
 | 
						|
environmental variables, etc.) and monitoring the stderr of the program.
 | 
						|
Since Go always outputs panics in a predictable way with a predictable
 | 
						|
exit code, panicwrap is able to reliably detect panics and allow the parent
 | 
						|
process to handle them.
 | 
						|
 | 
						|
## WHY?! Panics should CRASH!
 | 
						|
 | 
						|
Yes, panics _should_ crash. They are 100% always indicative of bugs.
 | 
						|
However, in some cases, such as user-facing programs (programs like
 | 
						|
[Packer](http://github.com/mitchellh/packer) or
 | 
						|
[Docker](http://github.com/dotcloud/docker)), it is up to the user to
 | 
						|
report such panics. This is unreliable, at best, and it would be better if the
 | 
						|
program could have a way to automatically report panics. panicwrap provides
 | 
						|
a way to do this.
 | 
						|
 | 
						|
For backend applications, it is easier to detect crashes (since the application
 | 
						|
exits). However, it is still nice sometimes to more intelligently log
 | 
						|
panics in some way. For example, at [HashiCorp](http://www.hashicorp.com),
 | 
						|
we use panicwrap to log panics to timestamped files with some additional
 | 
						|
data (configuration settings at the time, environmental variables, etc.)
 | 
						|
 | 
						|
The goal of panicwrap is _not_ to hide panics. It is instead to provide
 | 
						|
a clean mechanism for handling them before bubbling the up to the user
 | 
						|
and ultimately crashing.
 |