logHandlerError logs structured error context before writing an HTTP error response. All handler-level errors pass through here to ensure consistent attribute naming (ERR-05).
(r *http.Request, w http.ResponseWriter, msg string, code int, attrs ...slog.Attr)
| 756 | // logHandlerError logs structured error context before writing an HTTP error response. |
| 757 | // All handler-level errors pass through here to ensure consistent attribute naming (ERR-05). |
| 758 | func (h *commitServiceHandler) logHandlerError(r *http.Request, w http.ResponseWriter, msg string, code int, attrs ...slog.Attr) { |
| 759 | protocol := "v1beta1" |
| 760 | if !strings.Contains(r.URL.Path, "v1beta1") { |
| 761 | protocol = "v1" |
| 762 | } |
| 763 | |
| 764 | logAttrs := []slog.Attr{ |
| 765 | slog.String("server", h.api.domain), |
| 766 | slog.String("protocol", protocol), |
| 767 | slog.String("request_id", RequestIDFrom(r.Context())), |
| 768 | slog.String("error", msg), |
| 769 | slog.Int("status", code), |
| 770 | slog.String("error_class", errorClass(code)), |
| 771 | } |
| 772 | logAttrs = append(logAttrs, attrs...) |
| 773 | |
| 774 | level := slog.LevelWarn |
| 775 | if code >= 500 { |
| 776 | level = slog.LevelError |
| 777 | } |
| 778 | h.api.log.LogAttrs(r.Context(), level, "handler error", logAttrs...) |
| 779 | |
| 780 | http.Error(w, msg, code) |
| 781 | } |
| 782 | |
| 783 | // errorClass maps an HTTP status code to a short, grep-friendly class name |
| 784 | // used in structured logs. Three buckets only: |
no test coverage detected