Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions imageproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"time"

"github.com/gregjones/httpcache"
"github.com/prometheus/client_golang/prometheus/promhttp"
tphttp "willnorris.com/go/imageproxy/third_party/http"
)

Expand Down Expand Up @@ -115,11 +116,19 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

if r.URL.Path == "/metrics" {
var h http.Handler = promhttp.Handler()
h.ServeHTTP(w, r)
return
}

var h http.Handler = http.HandlerFunc(p.serveImage)
if p.Timeout > 0 {
h = tphttp.TimeoutHandler(h, p.Timeout, "Gateway timeout waiting for remote resource.")
}
start := time.Now()
h.ServeHTTP(w, r)
httpRequestsResponseTime.Observe(float64(time.Since(start).Seconds()))
}

// serveImage handles incoming requests for proxied images.
Expand All @@ -146,6 +155,7 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
msg := fmt.Sprintf("error fetching remote image: %v", err)
log.Print(msg)
http.Error(w, msg, http.StatusInternalServerError)
remoteImageFetchErrors.Inc()
return
}
defer resp.Body.Close()
Expand All @@ -155,6 +165,10 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
log.Printf("request: %v (served from cache: %v)", *req, cached == "1")
}

if cached == "1" {
requestServedFromCacheCount.Inc()
}

copyHeader(w.Header(), resp.Header, "Cache-Control", "Last-Modified", "Expires", "Etag", "Link")

if should304(r, resp) {
Expand Down
33 changes: 33 additions & 0 deletions metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package imageproxy

import (
"github.com/prometheus/client_golang/prometheus"
)

var (
requestServedFromCacheCount = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "requests_served_from_cache",
Help: "Number of requests served from cache.",
})
imageTransformationSummary = prometheus.NewSummary(prometheus.SummaryOpts{
Name: "image_transformation_seconds",
Help: "Time taken for image transformations in seconds.",
})
remoteImageFetchErrors = prometheus.NewCounter(prometheus.CounterOpts{
Name: "remote_image_fetch_errors",
Help: "Total image fetch failures",
})
httpRequestsResponseTime = prometheus.NewSummary(prometheus.SummaryOpts{
Namespace: "http",
Name: "response_time_seconds",
Help: "Request response times",
})
)

func init() {
prometheus.MustRegister(imageTransformationSummary)
prometheus.MustRegister(requestServedFromCacheCount)
prometheus.MustRegister(remoteImageFetchErrors)
prometheus.MustRegister(httpRequestsResponseTime)
}
3 changes: 3 additions & 0 deletions transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"io"
"log"
"math"
"time"

"github.com/disintegration/imaging"
"github.com/muesli/smartcrop"
Expand Down Expand Up @@ -269,6 +270,7 @@ func transformImage(m image.Image, opt Options) image.Image {
// Parse crop and resize parameters before applying any transforms.
// This is to ensure that any percentage-based values are based off the
// size of the original image.
start := time.Now()
rect := cropParams(m, opt)
w, h, resize := resizeParams(m, opt)

Expand Down Expand Up @@ -308,5 +310,6 @@ func transformImage(m image.Image, opt Options) image.Image {
m = imaging.FlipH(m)
}

imageTransformationSummary.Observe(float64(time.Since(start).Seconds()))
return m
}
20 changes: 20 additions & 0 deletions vendor/github.com/beorn7/perks/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading