Files
2024-10-21 15:19:45 +11:00

77 lines
2.2 KiB
Go

// server/middleware/logger.go
package middleware
import (
"net/http"
"strings"
"time"
"codeberg.org/vnpower/pixivfe/v2/audit"
"codeberg.org/vnpower/pixivfe/v2/config"
"codeberg.org/vnpower/pixivfe/v2/server/request_context"
)
// ResponseWriterInterceptStatus wraps http.ResponseWriter to intercept the status code.
type ResponseWriterInterceptStatus struct {
statusCode int
http.ResponseWriter
}
// WriteHeader intercepts the status code before writing it to the response.
func (w *ResponseWriterInterceptStatus) WriteHeader(code int) {
w.statusCode = code
w.ResponseWriter.WriteHeader(code)
}
// CanRequestSkipLogger determines if a request should bypass the logging middleware.
// This is useful for reducing log clutter from static assets and development-specific routes.
func CanRequestSkipLogger(r *http.Request) bool {
// NOTE: Uncomment the following line to log all requests
// return false
path := r.URL.Path
return strings.HasPrefix(path, "/img/") ||
strings.HasPrefix(path, "/css/") ||
strings.HasPrefix(path, "/js/") ||
strings.HasPrefix(path, "/diagnostics") ||
(config.GlobalConfig.InDevelopment &&
(strings.HasPrefix(path, "/proxy/s.pximg.net/") || strings.HasPrefix(path, "/proxy/i.pximg.net/")))
}
// LogRequest is a middleware that logs incoming HTTP requests and their corresponding responses.
func LogRequest(auditor *audit.Auditor) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if CanRequestSkipLogger(r) {
// If skipping, simply call the next handler without logging
next.ServeHTTP(w, r)
return
}
// Wrap the ResponseWriter to capture the status code
wrappedWriter := &ResponseWriterInterceptStatus{
ResponseWriter: w,
}
startTime := time.Now()
next.ServeHTTP(wrappedWriter, r)
endTime := time.Now()
ctx := request_context.Get(r)
auditor.LogServerRoundTrip(audit.ServerRequestSpan{
StartTime: startTime,
EndTime: endTime,
RequestId: ctx.RequestId,
Method: r.Method,
Path: r.URL.Path,
Status: wrappedWriter.statusCode,
Referer: r.Referer(),
RemoteAddr: r.RemoteAddr,
ErrorField: ctx.CaughtError,
})
})
}
}