Comprehensive error reporting is a system for collecting and analyzing errors in production.
1import (2 "errors"3 "fmt"4 "runtime/debug"5)67// Structured error8type AppError struct {9 Code string `json:"code"`10 Message string `json:"message"`11 Err error `json:"-"`12 Stack string `json:"stack,omitempty"`13 Context map[string]interface{} `json:"context,omitempty"`14 Severity string `json:"severity"`15}1617func (e *AppError) Error() string {18 if e.Err != nil {19 return fmt.Sprintf("[%s] %s: %v", e.Code, e.Message, e.Err)20 }21 return fmt.Sprintf("[%s] %s", e.Code, e.Message)22}2324func (e *AppError) Unwrap() error {25 return e.Err26}2728// Error factory29func NewError(code, message string, err error, severity string) *AppError {30 return &AppError{31 Code: code,32 Message: message,33 Err: err,34 Stack: string(debug.Stack()),35 Severity: severity,36 Context: make(map[string]interface{}),37 }38}3940func (e *AppError) WithContext(key string, value interface{}) *AppError {41 e.Context[key] = value42 return e43}4445// Usage46func GetUser(ctx context.Context, id int) (*User, error) {47 user, err := db.Find(ctx, id)48 if err != nil {49 return nil, NewError("USER_NOT_FOUND",50 "user not found", err, "warning").51 WithContext("user_id", id).52 WithContext("operation", "GetUser")53 }54 return user, nil55}5657// Reporter58type ErrorReporter interface {59 Report(err error)60}6162// Sentry integration63import "github.com/getsentry/sentry-go"6465type SentryReporter struct{}6667func (r *SentryReporter) Report(err error) {68 if appErr, ok := err.(*AppError); ok {69 sentry.WithScope(func(scope *sentry.Scope) {70 scope.SetTag("code", appErr.Code)71 scope.SetTag("severity", appErr.Severity)72 for k, v := range appErr.Context {73 scope.SetExtra(k, v)74 }75 sentry.CaptureException(appErr)76 })77 } else {78 sentry.CaptureException(err)79 }80}8182// HTTP error handling83func handleError(w http.ResponseWriter, err error) {84 var appErr *AppError85 if errors.As(err, &appErr) {86 // Sending to Sentry87 reporter.Report(appErr)8889 // HTTP response90 w.Header().Set("Content-Type", "application/json")91 w.WriteHeader(getStatusCode(appErr.Code))92 json.NewEncoder(w).Encode(appErr)93 } else {94 reporter.Report(err)95 http.Error(w, "Internal Server Error", 500)96 }97}
Components: