brandur.org

Global recovery in Go with defer

Having spent the last few weeks trying to become literate in Golang, I can confidently say that all of my favorite tricks in the language involved the defer statement. Here’s one that I gleaned from the source code of hk:

package main

import (
	"fmt"
	"log"
	"os"
)

var (
	logger *log.Logger
)

func init() {
	f, _ := os.Create("log")
	logger = log.New(f, "", log.LstdFlags)
}

func main() {
	defer recoverPanic()
	panic(fmt.Errorf("This unhandled error will be handled"))
}

func recoverPanic() {
	if rec := recover(); rec != nil {
		err := rec.(error)
		logger.Printf("Unhandled error: %v\n", err.Error())
		fmt.Fprintf(os.Stderr, "Program quit unexpectedly; please check your logs\n")
		os.Exit(1)
	}
}

The output of this program is:

$ ./recover
Program quit unexpectedly; please check your logs

$ echo $?
1

$ cat log
2014/09/21 11:13:11 Unhandled error: This unhandled error will be handled

In this simplified example above, we use a combination of defer and recover() to handle any exception that might have been thrown with panic(), log some information about it, and exit the program cleanly.

hk takes this a step further by sending the error up to Rollbar so that all of its unexpected crashes can be examined in aggregate.

Did I make a mistake? Please consider sending a pull request.