-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docd: add recovery middleware and allow reporting errors to GCP (#121)
- Loading branch information
1 parent
e52737e
commit 6d8c9df
Showing
5 changed files
with
761 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package internal | ||
|
||
import ( | ||
"io" | ||
|
||
"cloud.google.com/go/errorreporting" | ||
) | ||
|
||
// ErrorReporter reports errors. | ||
type ErrorReporter interface { | ||
Report(errorreporting.Entry) | ||
io.Closer | ||
} | ||
|
||
// NopErrorReporter is a no-op reporter. | ||
type NopErrorReporter struct{} | ||
|
||
var _ ErrorReporter = (*NopErrorReporter)(nil) | ||
|
||
// Report implements ErrorReporter. | ||
func (r *NopErrorReporter) Report(e errorreporting.Entry) {} | ||
|
||
// Close implements ErrorReporter. | ||
func (r *NopErrorReporter) Close() error { return nil } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package internal | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"runtime/debug" | ||
|
||
"cloud.google.com/go/errorreporting" | ||
) | ||
|
||
type recoveryHandler struct { | ||
er ErrorReporter | ||
handler http.Handler | ||
} | ||
|
||
// RecoveryHandler is HTTP middleware that recovers from a panic, writes a | ||
// 500, reports the panic, logs the panic and continues to the next handler. | ||
func RecoveryHandler(er ErrorReporter) func(h http.Handler) http.Handler { | ||
return func(h http.Handler) http.Handler { | ||
return &recoveryHandler{er: er, handler: h} | ||
} | ||
} | ||
|
||
func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||
defer func() { | ||
if rec := recover(); rec != nil { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
w.Write([]byte(`{"error":"internal server error"}`)) | ||
h.handle(req, &recovered{rec, debug.Stack()}) | ||
} | ||
}() | ||
|
||
h.handler.ServeHTTP(w, req) | ||
} | ||
|
||
func (h recoveryHandler) handle(r *http.Request, err error) { | ||
stack, _ := stackFromRecovered(err) | ||
|
||
e := errorreporting.Entry{ | ||
Error: err, | ||
Stack: stack, | ||
Req: r, | ||
} | ||
h.er.Report(e) | ||
|
||
log.Println(err) | ||
log.Printf("%s", stack) | ||
} | ||
|
||
// recovered represents the return value from a call to recover. | ||
type recovered struct { | ||
// p is the error value passed to the call of panic. | ||
p interface{} | ||
// stack is the panic stack trace. | ||
stack []byte | ||
} | ||
|
||
var _ error = (*recovered)(nil) | ||
|
||
// Error implements error. | ||
func (e *recovered) Error() string { | ||
if err, ok := e.p.(error); ok { | ||
return err.Error() | ||
} | ||
return fmt.Sprintf("panic: %v", e.p) | ||
} | ||
|
||
// stackFromRecovered returns a stack trace and true if the recovdered has a | ||
// stack trace created by this package. | ||
// | ||
// Otherwise it returns nil and false. | ||
func stackFromRecovered(err error) ([]byte, bool) { | ||
var rec *recovered | ||
if errors.As(err, &rec) { | ||
return rec.stack, true | ||
} | ||
return nil, false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.