kubernetes apiserver源码: panic & recover

343 阅读1分钟
package main

import (
	"errors"
	"fmt"
	"net/http"
	"runtime"
)

func main() {
	Hello()

        // 这里将继续执行
	fmt.Println("keep going")
}


func Hello(){

	defer HandleCrash()

	panic(errors.New("no hello"))
}

// HandleCrash simply catches a crash and logs an error. 
// E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully.
func HandleCrash(additionalHandlers ...func(interface{})) {
	if r := recover(); r != nil {
		logPanic(r)
	}
}


// logPanic logs the caller tree when a panic occurs 
func logPanic(r interface{}) {
	if r == http.ErrAbortHandler {
		// honor the http.ErrAbortHandler sentinel panic value:
		//   ErrAbortHandler is a sentinel panic value to abort a handler.
		//   While any panic from ServeHTTP aborts the response to the client,
		//   panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log.
		return
	}

	// Same as stdlib http server code. Manually allocate stack trace buffer size
	// to prevent excessively large logs
	const size = 64 << 10
	stacktrace := make([]byte, size)
	stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
	if _, ok := r.(string); ok {
		fmt.Printf("Observed a panic: %s\n%s", r, stacktrace)
	} else {
		fmt.Printf("Observed a panic: %#v (%v)\n%s", r, r, stacktrace)
	}
}

输出:

  • 当出现panic时,recover会恢复程序执行
  • 打印出完整的调用栈
Observed a panic: &errors.errorString{s:"no hello"} (no hello)
goroutine 1 [running]:
main.logPanic({0x51a680, 0xc000012c10})
/root/go/src/awesomeProject/test/main.go:58 +0x99
main.HandleCrash({0x0, 0xc0000445f8, 0x26})
/root/go/src/awesomeProject/test/main.go:39 +0x2a
panic({0x51a680, 0xc000012c10})
/usr/local/go/src/runtime/panic.go:1038 +0x215
main.Hello()
/root/go/src/awesomeProject/test/main.go:28 +0x8f
main.main()
/root/go/src/awesomeProject/test/main.go:16 +0x19
keep going

这串代码可以用于web服务的崩溃恢复.