add Cloudflare R2 storage integration and update bug report handling
Some checks failed
Build & Publish Docker Image / build-and-push (push) Failing after 11s
Some checks failed
Build & Publish Docker Image / build-and-push (push) Failing after 11s
This commit is contained in:
62
internal/middleware/timing.go
Normal file
62
internal/middleware/timing.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"emly-api-go/internal/timing"
|
||||
)
|
||||
|
||||
// Timing is a middleware that measures per-request step durations.
|
||||
//
|
||||
// It injects a *timing.Timer into the request context so that handlers can
|
||||
// record named checkpoints with timing.Mark(r.Context(), "step_name").
|
||||
// After the handler returns, it logs a single line of the form:
|
||||
//
|
||||
// [TIMING] METHOD /path step1=1.2ms step2=18ms total=20ms
|
||||
//
|
||||
// Each step duration is measured from the previous checkpoint (or request
|
||||
// start for the first one), so the values add up to the total.
|
||||
func Timing(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, t := timing.NewContext(r.Context())
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
total := time.Since(t.Start)
|
||||
checkpoints := t.Checkpoints()
|
||||
|
||||
if len(checkpoints) == 0 {
|
||||
// No checkpoints: just log the total so every request is visible.
|
||||
log.Printf("[TIMING] %s %s total=%s", r.Method, r.URL.Path, round(total))
|
||||
return
|
||||
}
|
||||
|
||||
parts := make([]string, 0, len(checkpoints)+1)
|
||||
prev := t.Start
|
||||
for _, cp := range checkpoints {
|
||||
parts = append(parts, fmt.Sprintf("%s=%s", cp.Name, round(cp.At.Sub(prev))))
|
||||
prev = cp.At
|
||||
}
|
||||
// Remainder after the last checkpoint.
|
||||
if tail := total - prev.Sub(t.Start); tail > 0 {
|
||||
parts = append(parts, fmt.Sprintf("response=%s", round(tail)))
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("total=%s", round(total)))
|
||||
|
||||
log.Printf("[TIMING] %s %s %s", r.Method, r.URL.Path, strings.Join(parts, " "))
|
||||
})
|
||||
}
|
||||
|
||||
func round(d time.Duration) string {
|
||||
switch {
|
||||
case d < time.Microsecond:
|
||||
return fmt.Sprintf("%dns", d.Nanoseconds())
|
||||
case d < time.Millisecond:
|
||||
return fmt.Sprintf("%.2fµs", float64(d.Nanoseconds())/1e3)
|
||||
default:
|
||||
return fmt.Sprintf("%.2fms", float64(d.Nanoseconds())/1e6)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user