Files
cloud-services/pkg/loggerdataresp/data_error_resp.go

197 lines
5.1 KiB
Go

package loggerdataresp
import (
"io"
"net"
"net/http"
"strings"
"fiskerinc.com/modules/common/staticerrors"
er "fiskerinc.com/modules/errors"
e "fiskerinc.com/modules/mongo/error"
"fiskerinc.com/modules/validator"
"go.mongodb.org/mongo-driver/mongo"
"fiskerinc.com/modules/logger"
"fiskerinc.com/modules/utils"
cKafka "github.com/confluentinc/confluent-kafka-go/v2/kafka"
"github.com/go-pg/pg/v10"
"github.com/pkg/errors"
)
// Maybe if i move this out we will see all our problems solved
var MongoUpdateErrorCheck = ErrorCheck{Err: e.ErrUnableToUpdate, Status: http.StatusNotFound}
var MongoDeleteErrorCheck = ErrorCheck{Err: e.ErrUnableToDelete, Status: http.StatusNotFound}
var PostgresNoRowsErrorCheck = ErrorCheck{Err: pg.ErrNoRows, Status: http.StatusNotFound}
var EofErrorCheck = ErrorCheck{Err: io.EOF, Status: http.StatusNotFound}
var CustomErrorCheck = ErrorCheck{}
type ErrorCheck struct {
Err error
Status int
}
type respErr func(w http.ResponseWriter, status int, message string)
// log an error message without populating an HTTP response
func BadDataError(err error, options ...ErrorCheck) bool {
return badDataErrorResp(nil, err, 0, nil, options)
}
// log an error message and populate an HTTP response
func BadDataErrorResp(w http.ResponseWriter, err error, defaultStatus int, options ...ErrorCheck) bool {
return badDataErrorResp(w, err, defaultStatus, utils.RespError, options)
}
// log an error message and populate an XML HTTP response
func BadDataErrorXMLResp(w http.ResponseWriter, err error, defaultStatus int, options ...ErrorCheck) bool {
return badDataErrorResp(w, err, defaultStatus, utils.RespXMLError, options)
}
// log an error message and populate an JSON RPC response
func BadDataErrorJSONRPCResp(w http.ResponseWriter, errRPC error, err error) bool {
if err == nil {
return false
}
utils.RespJSONRPCError(w, errRPC, err.Error())
if errRPC == utils.ErrJSONRPCServerError || errRPC == utils.ErrJSONRPCInternalError {
logger.Error().Err(err).Send()
} else {
logger.Warn().Err(err).Send()
}
return true
}
func badDataErrorResp(w http.ResponseWriter, err error, defaultStatus int, errFunc respErr, errorChecks []ErrorCheck) bool {
if err == nil {
return false
}
cause := errors.Cause(err)
if ok, msg := validator.GetValidationErrorMsg(cause); ok {
logError(err, msg, http.StatusBadRequest, errFunc, w)
return true
}
if customErr, ok := cause.(*er.CustomError); ok {
logError(customErr.Err(), customErr.Message, customErr.Status, errFunc, w)
return true
}
for _, errorCheck := range errorChecks {
if errors.Is(errorCheck.Err, cause) {
logError(errorCheck.Err, errorCheck.Err.Error(), errorCheck.Status, errFunc, w)
return true
}
}
if handleMongoErrors(err, errFunc, w) {
return true
}
if handlePgErrors(err, errFunc, w) {
return true
}
if handleRedisErrors(err, errFunc, w) {
return true
}
if handleSAPErrors(err, errFunc, w) {
return true
}
if handleKafkaErrors(err, errFunc, w) {
return true
}
logError(err, err.Error(), defaultStatus, errFunc, w)
return true
}
func handleMongoErrors(err error, errFunc respErr, w http.ResponseWriter) bool {
if mongo.IsDuplicateKeyError(err) {
logError(err, err.Error(), http.StatusBadRequest, errFunc, w)
return true
}
if mongo.IsTimeout(err) {
logError(err, err.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
if mongo.IsNetworkError(err) {
logError(err, err.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
return false
}
func handlePgErrors(err error, errFunc respErr, w http.ResponseWriter) bool {
if pgErr, ok := err.(pg.Error); ok {
switch pgErr.Field('V') {
case "FATAL", "PANIC":
logError(pgErr, pgErr.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
}
return false
}
func handleRedisErrors(err error, errFunc respErr, w http.ResponseWriter) bool {
if opError, ok := err.(*net.OpError); ok {
logError(opError, opError.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
if dnsError, ok := err.(*net.DNSError); ok {
logError(dnsError, dnsError.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
return false
}
func handleSAPErrors(err error, errFunc respErr, w http.ResponseWriter) bool {
if strings.HasPrefix(err.Error(), staticerrors.ErrorSAPFailedCall) {
logError(err, err.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
return false
}
func handleKafkaErrors(err error, errFunc respErr, w http.ResponseWriter) bool {
if kafkaErr, ok := err.(cKafka.Error); ok {
if kafkaErr.IsFatal() {
logError(kafkaErr, kafkaErr.Error(), http.StatusServiceUnavailable, errFunc, w)
return true
}
}
return false
}
func logError(err error, errMessage string, status int, errFunc respErr, w http.ResponseWriter) {
switch status {
case http.StatusServiceUnavailable, http.StatusInternalServerError:
logger.Error().Err(err).Send()
case http.StatusNotFound, http.StatusBadRequest, http.StatusForbidden:
logger.Warn().Err(err).Send()
default:
logger.Warn().Err(err).Send()
}
if errFunc != nil && w != nil {
errFunc(w, status, errMessage)
}
}