Better error metrics

This commit is contained in:
DarthSim
2022-07-20 15:49:05 +06:00
parent 1524a0e973
commit 20039f49a5
8 changed files with 95 additions and 73 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"net/http"
"net/http/cookiejar"
@@ -144,6 +145,33 @@ func respondWithNotModified(reqID string, r *http.Request, rw http.ResponseWrite
)
}
func sendErrAndPanic(ctx context.Context, errType string, err error) {
send := true
if ierr, ok := err.(*ierrors.Error); ok {
switch ierr.StatusCode {
case http.StatusServiceUnavailable:
errType = "timeout"
case 499:
// Don't need to send a "request cancelled" error
send = false
}
}
if send {
metrics.SendError(ctx, errType, err)
}
panic(err)
}
func checkErr(ctx context.Context, errType string, err error) {
if err == nil {
return
}
sendErrAndPanic(ctx, errType, err)
}
func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -163,25 +191,29 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
signature = path[:signatureEnd]
path = path[signatureEnd:]
} else {
panic(ierrors.New(404, fmt.Sprintf("Invalid path: %s", path), "Invalid URL"))
sendErrAndPanic(ctx, "path_parsing", ierrors.New(
404, fmt.Sprintf("Invalid path: %s", path), "Invalid URL",
))
}
if err := security.VerifySignature(signature, path); err != nil {
panic(ierrors.New(403, err.Error(), "Forbidden"))
sendErrAndPanic(ctx, "security", ierrors.New(403, err.Error(), "Forbidden"))
}
po, imageURL, err := options.ParsePath(path, r.Header)
if err != nil {
panic(err)
}
checkErr(ctx, "path_parsing", err)
if !security.VerifySourceURL(imageURL) {
panic(ierrors.New(404, fmt.Sprintf("Source URL is not allowed: %s", imageURL), "Invalid source"))
sendErrAndPanic(ctx, "security", ierrors.New(
404,
fmt.Sprintf("Source URL is not allowed: %s", imageURL),
"Invalid source",
))
}
// SVG is a special case. Though saving to svg is not supported, SVG->SVG is.
if !vips.SupportsSave(po.Format) && po.Format != imagetype.Unknown && po.Format != imagetype.SVG {
panic(ierrors.New(
sendErrAndPanic(ctx, "path_parsing", ierrors.New(
422,
fmt.Sprintf("Resulting image format is not supported: %s", po.Format),
"Invalid URL",
@@ -209,7 +241,7 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
// We don't actually need to check timeout here,
// but it's an easy way to check if this is an actual timeout
// or the request was cancelled
router.CheckTimeout(ctx)
checkErr(ctx, "queue", router.CheckTimeout(ctx))
}
defer func() { <-processingSem }()
@@ -221,9 +253,8 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
var cookieJar *cookiejar.Jar
if config.CookiePassthrough {
if cookieJar, err = cookies.JarFromRequest(r); err != nil {
panic(err)
}
cookieJar, err = cookies.JarFromRequest(r)
checkErr(ctx, "download", err)
}
return imagedata.Download(imageURL, "source image", imgRequestHeader, cookieJar)
@@ -258,7 +289,7 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
originData = imagedata.FallbackImage
}
router.CheckTimeout(ctx)
checkErr(ctx, "timeout", router.CheckTimeout(ctx))
if config.ETagEnabled && statusCode == http.StatusOK {
imgDataMatch := etagHandler.SetActualImageData(originData)
@@ -271,16 +302,14 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
}
}
router.CheckTimeout(ctx)
checkErr(ctx, "timeout", router.CheckTimeout(ctx))
if originData.Type == po.Format || po.Format == imagetype.Unknown {
// Don't process SVG
if originData.Type == imagetype.SVG {
if config.SanitizeSvg {
sanitized, svgErr := svg.Satitize(originData.Data)
if svgErr != nil {
panic(svgErr)
}
checkErr(ctx, "svg_processing", svgErr)
// Since we'll replace origin data, it's better to close it to return
// it's buffer to the pool
@@ -307,7 +336,7 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
}
if !vips.SupportsLoad(originData.Type) {
panic(ierrors.New(
sendErrAndPanic(ctx, "processing", ierrors.New(
422,
fmt.Sprintf("Source image format is not supported: %s", originData.Type),
"Invalid URL",
@@ -316,20 +345,20 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
// At this point we can't allow requested format to be SVG as we can't save SVGs
if po.Format == imagetype.SVG {
panic(ierrors.New(422, "Resulting image format is not supported: svg", "Invalid URL"))
sendErrAndPanic(ctx, "processing", ierrors.New(
422, "Resulting image format is not supported: svg", "Invalid URL",
))
}
resultData, err := func() (*imagedata.ImageData, error) {
defer metrics.StartProcessingSegment(ctx)()
return processing.ProcessImage(ctx, originData, po)
}()
if err != nil {
metrics.SendError(ctx, "processing", err)
panic(err)
}
checkErr(ctx, "processing", err)
defer resultData.Close()
router.CheckTimeout(ctx)
checkErr(ctx, "timeout", router.CheckTimeout(ctx))
respondWithImage(reqID, r, rw, statusCode, resultData, po, imageURL, originData)
}