mirror of https://github.com/portainer/portainer
62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
// Package error provides error/logging functions that can be used in conjuction with http.Handler.
|
|
package error
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"unicode"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/segmentio/encoding/json"
|
|
)
|
|
|
|
type (
|
|
// LoggerHandler defines a HTTP handler that includes a HandlerError return pointer
|
|
LoggerHandler func(http.ResponseWriter, *http.Request) *HandlerError
|
|
|
|
errorResponse struct {
|
|
Message string `json:"message,omitempty"`
|
|
Details string `json:"details,omitempty"`
|
|
}
|
|
)
|
|
|
|
func (handler LoggerHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|
err := handler(rw, r)
|
|
if err != nil {
|
|
writeErrorResponse(rw, err)
|
|
}
|
|
}
|
|
|
|
func capitalize(s string) string {
|
|
if len(s) == 0 {
|
|
return s
|
|
}
|
|
|
|
// Capitalize the first letter of the word or sentence
|
|
firstLetter := unicode.ToUpper(rune(s[0]))
|
|
return string(firstLetter) + s[1:]
|
|
}
|
|
|
|
func writeErrorResponse(rw http.ResponseWriter, err *HandlerError) {
|
|
if err.Err == nil {
|
|
err.Err = errors.New(capitalize(err.Message))
|
|
}
|
|
|
|
log.Debug().CallerSkipFrame(2).Err(err.Err).Int("status_code", err.StatusCode).Str("msg", err.Message).Msg("HTTP error")
|
|
|
|
rw.Header().Set("Content-Type", "application/json")
|
|
rw.WriteHeader(err.StatusCode)
|
|
|
|
enc := json.NewEncoder(rw)
|
|
enc.SetSortMapKeys(false)
|
|
enc.SetAppendNewline(false)
|
|
|
|
enc.Encode(&errorResponse{Message: err.Message, Details: capitalize(err.Err.Error())})
|
|
}
|
|
|
|
// WriteError is a convenience function that creates a new HandlerError before calling writeErrorResponse.
|
|
// For use outside of the standard http handlers.
|
|
func WriteError(rw http.ResponseWriter, code int, message string, err error) {
|
|
writeErrorResponse(rw, &HandlerError{code, message, err})
|
|
}
|