修复bug及添加日志打印
This commit is contained in:
@@ -104,7 +104,7 @@ func (s *Server) Handler() http.Handler {
|
||||
mux.Handle("GET /api/admin/history/batches/{id}", s.requireAdmin(http.HandlerFunc(s.adminHistoryBatch)))
|
||||
mux.Handle("GET /api/admin/history/summary", s.requireAdmin(http.HandlerFunc(s.adminHistorySummary)))
|
||||
mux.Handle("GET /api/admin/history/export.csv", s.requireAdmin(http.HandlerFunc(s.adminHistoryExport)))
|
||||
return s.recoverPanic(s.requestID(s.accessLog(s.securityHeaders(mux))))
|
||||
return s.requestID(s.accessLog(s.recoverPanic(s.securityHeaders(mux))))
|
||||
}
|
||||
|
||||
func (s *Server) health(w http.ResponseWriter, _ *http.Request) {
|
||||
@@ -144,32 +144,84 @@ func (s *Server) requestID(next http.Handler) http.Handler {
|
||||
|
||||
type statusRecorder struct {
|
||||
http.ResponseWriter
|
||||
status int
|
||||
status int
|
||||
wroteHeader bool
|
||||
body *logBodyCapture
|
||||
}
|
||||
|
||||
func (r *statusRecorder) WriteHeader(status int) {
|
||||
if r.wroteHeader {
|
||||
return
|
||||
}
|
||||
r.status = status
|
||||
r.wroteHeader = true
|
||||
r.ResponseWriter.WriteHeader(status)
|
||||
}
|
||||
|
||||
func (r *statusRecorder) Flush() {
|
||||
if flusher, ok := r.ResponseWriter.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
func (r *statusRecorder) Write(value []byte) (int, error) {
|
||||
if !r.wroteHeader {
|
||||
r.WriteHeader(http.StatusOK)
|
||||
}
|
||||
n, err := r.ResponseWriter.Write(value)
|
||||
if n > 0 && r.body != nil {
|
||||
_, _ = r.body.Write(value[:n])
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *statusRecorder) Unwrap() http.ResponseWriter {
|
||||
return r.ResponseWriter
|
||||
}
|
||||
|
||||
func (r *statusRecorder) responseStarted() bool {
|
||||
return r.wroteHeader
|
||||
}
|
||||
|
||||
type flushStatusRecorder struct {
|
||||
*statusRecorder
|
||||
}
|
||||
|
||||
func (r *flushStatusRecorder) Flush() {
|
||||
if !r.wroteHeader {
|
||||
r.WriteHeader(http.StatusOK)
|
||||
}
|
||||
r.ResponseWriter.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
func (s *Server) accessLog(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
started := s.now()
|
||||
recorder := &statusRecorder{ResponseWriter: w, status: http.StatusOK}
|
||||
next.ServeHTTP(recorder, r)
|
||||
s.logger.Info("http request",
|
||||
var requestBody *logBodyCapture
|
||||
var responseBody *logBodyCapture
|
||||
if shouldCaptureLogBody(r) {
|
||||
requestBody = &logBodyCapture{}
|
||||
responseBody = &logBodyCapture{}
|
||||
if r.Body != nil {
|
||||
r.Body = &logCaptureReadCloser{ReadCloser: r.Body, capture: requestBody}
|
||||
}
|
||||
}
|
||||
recorder := &statusRecorder{ResponseWriter: w, status: http.StatusOK, body: responseBody}
|
||||
var responseWriter http.ResponseWriter = recorder
|
||||
if _, ok := w.(http.Flusher); ok {
|
||||
responseWriter = &flushStatusRecorder{statusRecorder: recorder}
|
||||
}
|
||||
next.ServeHTTP(responseWriter, r)
|
||||
attributes := []any{
|
||||
"request_id", requestID(r.Context()),
|
||||
"method", r.Method,
|
||||
"path", r.URL.Path,
|
||||
"path", logPath(r),
|
||||
"status", recorder.status,
|
||||
"duration_ms", time.Since(started).Milliseconds(),
|
||||
)
|
||||
}
|
||||
if isImportantLogRoute(r) {
|
||||
if request := requestLogDetails(r, requestBody); request != nil {
|
||||
attributes = append(attributes, "request", request)
|
||||
}
|
||||
if response := responseLogDetails(r, recorder); response != nil {
|
||||
attributes = append(attributes, "response", response)
|
||||
}
|
||||
}
|
||||
s.logger.Info("http request", attributes...)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -187,7 +239,19 @@ func (s *Server) recoverPanic(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
s.logger.Error("panic recovered", "request_id", requestID(r.Context()), "error", recovered, "stack", string(debug.Stack()))
|
||||
responseStarted := false
|
||||
if state, ok := w.(interface{ responseStarted() bool }); ok {
|
||||
responseStarted = state.responseStarted()
|
||||
}
|
||||
s.logger.Error("panic recovered",
|
||||
"request_id", requestID(r.Context()),
|
||||
"error", recovered,
|
||||
"response_started", responseStarted,
|
||||
"stack", string(debug.Stack()),
|
||||
)
|
||||
if responseStarted {
|
||||
return
|
||||
}
|
||||
writeError(w, fmt.Errorf("panic: %v", recovered))
|
||||
}
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user