github.com/searKing/golang/go@v1.2.117/runtime/panic.go (about) 1 package runtime 2 3 import ( 4 "fmt" 5 "log" 6 "net/http" 7 ) 8 9 var ( 10 DefaultPanic = Panic{} 11 NeverPanic = Panic{IgnoreCrash: true} 12 LogPanic = Panic{PanicHandlers: []func(any){logPanic}} 13 NeverPanicButLog = Panic{IgnoreCrash: true, PanicHandlers: []func(any){logPanic}} 14 ) 15 16 // Panic simply catches a panic and logs an error. Meant to be called via 17 // defer. Additional context-specific handlers can be provided, and will be 18 // called in case of panic. 19 type Panic struct { 20 // IgnoreCrash controls the behavior of Recover and now defaults false. 21 // if false, crash immediately, rather than eating panics. 22 IgnoreCrash bool 23 24 // PanicHandlers for something like logging the panic message, shutting down go routines gracefully. 25 PanicHandlers []func(any) 26 } 27 28 // Recover actually crashes if IgnoreCrash is false, after calling PanicHandlers. 29 func (p Panic) Recover() { 30 if r := recover(); r != nil { 31 for _, fn := range p.PanicHandlers { 32 fn(r) 33 } 34 if p.IgnoreCrash { 35 return 36 } 37 // Actually proceed to panic. 38 panic(r) 39 } 40 } 41 42 func (p *Panic) AppendHandler(handlers ...func(any)) *Panic { 43 p.PanicHandlers = append(p.PanicHandlers, handlers...) 44 return p 45 } 46 47 func HandlePanicWith(handlers ...func(any)) Panic { 48 p := Panic{} 49 p.AppendHandler(handlers...) 50 return p 51 } 52 53 // RecoverFromPanic replaces the specified error with an error containing the 54 // original error, and the call tree when a panic occurs. This enables error 55 // handlers to handle errors and panics the same way. 56 func RecoverFromPanic(err error) error { 57 if r := recover(); r != nil { 58 const size = 64 << 10 59 stacktrace := GetCallStack(size) 60 if err == nil { 61 return fmt.Errorf( 62 "recovered from panic %q. Call stack:\n%s", 63 r, 64 stacktrace) 65 } 66 67 return fmt.Errorf( 68 "recovered from panic %q. (err=%w) Call stack:\n%s", 69 r, 70 err, 71 stacktrace) 72 } 73 return err 74 } 75 76 // logPanic logs the caller tree when a panic occurs (except in the special case of http.ErrAbortHandler). 77 func logPanic(r any) { 78 if r == http.ErrAbortHandler { 79 // honor the http.ErrAbortHandler sentinel panic value: 80 // ErrAbortHandler is a sentinel panic value to abort a handler. 81 // While any panic from ServeHTTP aborts the response to the client, 82 // panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log. 83 return 84 } 85 86 const size = 64 << 10 87 stacktrace := GetCallStack(size) 88 if _, ok := r.(string); ok { 89 log.Printf("Observed a panic: %s\n%s", r, stacktrace) 90 } else { 91 log.Printf("Observed a panic: %#v (%v)\n%s", r, r, stacktrace) 92 } 93 }