errors.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package main
  2. import (
  3. "fmt"
  4. "runtime"
  5. "strings"
  6. )
  7. type imgproxyError struct {
  8. StatusCode int
  9. Message string
  10. PublicMessage string
  11. Unexpected bool
  12. stack []uintptr
  13. }
  14. func (e *imgproxyError) Error() string {
  15. return e.Message
  16. }
  17. func (e *imgproxyError) ErrorWithStack() string {
  18. if e.stack == nil {
  19. return e.Message
  20. }
  21. return fmt.Sprintf("%s\n%s", e.Message, formatStack(e.stack))
  22. }
  23. func (e *imgproxyError) StackTrace() []uintptr {
  24. return e.stack
  25. }
  26. func newError(status int, msg string, pub string) *imgproxyError {
  27. return &imgproxyError{
  28. StatusCode: status,
  29. Message: msg,
  30. PublicMessage: pub,
  31. }
  32. }
  33. func newUnexpectedError(msg string, skip int) *imgproxyError {
  34. return &imgproxyError{
  35. StatusCode: 500,
  36. Message: msg,
  37. PublicMessage: "Internal error",
  38. Unexpected: true,
  39. stack: callers(skip + 3),
  40. }
  41. }
  42. func callers(skip int) []uintptr {
  43. stack := make([]uintptr, 10)
  44. n := runtime.Callers(skip, stack)
  45. return stack[:n]
  46. }
  47. func formatStack(stack []uintptr) string {
  48. lines := make([]string, len(stack))
  49. for i, pc := range stack {
  50. f := runtime.FuncForPC(pc)
  51. file, line := f.FileLine(pc)
  52. lines[i] = fmt.Sprintf("%s:%d %s", file, line, f.Name())
  53. }
  54. return strings.Join(lines, "\n")
  55. }