Files
2026-07-27 19:31:43 +08:00

79 lines
1.9 KiB
Go

package api
import (
"context"
"log/slog"
"net/http"
"strings"
chimw "github.com/go-chi/chi/v5/middleware"
"litepan/internal/domain"
)
type requestLoggerCtxKey struct{}
func (h *Handler) attachRequestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := h.log
if log == nil {
log = slog.Default()
}
if reqID := chimw.GetReqID(r.Context()); reqID != "" {
log = log.With("request_id", reqID)
}
ctx := context.WithValue(r.Context(), requestLoggerCtxKey{}, log)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func requestLogger(ctx context.Context) *slog.Logger {
if ctx == nil {
return slog.Default()
}
if log, ok := ctx.Value(requestLoggerCtxKey{}).(*slog.Logger); ok && log != nil {
return log
}
return slog.Default()
}
func logAPIError(r *http.Request, err error) {
if r == nil || err == nil {
return
}
log := requestLogger(r.Context())
fields := []any{
"method", r.Method,
"path", r.URL.Path,
"raw_err", err.Error(),
}
if raw := strings.TrimSpace(r.URL.RawQuery); raw != "" {
fields = append(fields, "query", raw)
}
if accountID := strings.TrimSpace(r.URL.Query().Get("account_id")); accountID != "" {
fields = append(fields, "account_id", accountID)
}
if ae, ok := domain.AsAppError(err); ok {
fields = append(fields,
"status", ae.HTTPStatus(),
"error_type", ae.Code,
"message", ae.Message,
)
if details := detailsOrNil(ae.Details); details != nil {
fields = append(fields, "details", details)
}
switch ae.Code {
case domain.CodeInternal, domain.CodeDriverError:
log.Error("API 请求失败", fields...)
default:
log.Warn("API 请求失败", fields...)
}
return
}
log.Error("API 请求失败", append(fields,
"status", http.StatusInternalServerError,
"error_type", domain.CodeInternal,
"message", "服务内部错误",
)...)
}