Download internal/log/http.go from SaylorTwift/crush: direct link, hf CLI and curl.
- Browser
- Download file 3.09 kB
-
https://huggingface.co/SaylorTwift/crush/resolve/main/internal/log/http.go
- Command line
-
hf download hf://SaylorTwift/crush/internal/log/http.go
-
curl -L -o http.go https://huggingface.co/SaylorTwift/crush/resolve/main/internal/log/http.go
3.09 kB
| package log | |
| import ( | |
| "bytes" | |
| "encoding/json" | |
| "io" | |
| "log/slog" | |
| "net/http" | |
| "strings" | |
| "time" | |
| ) | |
| // NewHTTPClient creates an HTTP client with debug logging enabled when debug mode is on. | |
| func NewHTTPClient() *http.Client { | |
| return &http.Client{ | |
| Transport: &HTTPRoundTripLogger{ | |
| Transport: http.DefaultTransport, | |
| }, | |
| } | |
| } | |
| // HTTPRoundTripLogger is an http.RoundTripper that logs requests and responses. | |
| type HTTPRoundTripLogger struct { | |
| Transport http.RoundTripper | |
| } | |
| // RoundTrip implements http.RoundTripper interface with logging. | |
| func (h *HTTPRoundTripLogger) RoundTrip(req *http.Request) (*http.Response, error) { | |
| var err error | |
| var save io.ReadCloser | |
| save, req.Body, err = drainBody(req.Body) | |
| if err != nil { | |
| slog.Error( | |
| "HTTP request failed", | |
| "method", req.Method, | |
| "url", req.URL, | |
| "error", err, | |
| ) | |
| return nil, err | |
| } | |
| if slog.Default().Enabled(req.Context(), slog.LevelDebug) { | |
| slog.Debug( | |
| "HTTP Request", | |
| "method", req.Method, | |
| "url", req.URL, | |
| "body", bodyToString(save), | |
| ) | |
| } | |
| start := time.Now() | |
| resp, err := h.Transport.RoundTrip(req) | |
| duration := time.Since(start) | |
| if err != nil { | |
| slog.Error( | |
| "HTTP request failed", | |
| "method", req.Method, | |
| "url", req.URL, | |
| "duration_ms", duration.Milliseconds(), | |
| "error", err, | |
| ) | |
| return resp, err | |
| } | |
| save, resp.Body, err = drainBody(resp.Body) | |
| if err != nil { | |
| slog.Error("Failed to drain response body", "error", err) | |
| return resp, err | |
| } | |
| if slog.Default().Enabled(req.Context(), slog.LevelDebug) { | |
| slog.Debug( | |
| "HTTP Response", | |
| "status_code", resp.StatusCode, | |
| "status", resp.Status, | |
| "headers", formatHeaders(resp.Header), | |
| "body", bodyToString(save), | |
| "content_length", resp.ContentLength, | |
| "duration_ms", duration.Milliseconds(), | |
| ) | |
| } | |
| return resp, nil | |
| } | |
| func bodyToString(body io.ReadCloser) string { | |
| if body == nil { | |
| return "" | |
| } | |
| src, err := io.ReadAll(body) | |
| if err != nil { | |
| slog.Error("Failed to read body", "error", err) | |
| return "" | |
| } | |
| var b bytes.Buffer | |
| if json.Indent(&b, bytes.TrimSpace(src), "", " ") != nil { | |
| // not json probably | |
| return string(src) | |
| } | |
| return b.String() | |
| } | |
| // formatHeaders formats HTTP headers for logging, filtering out sensitive information. | |
| func formatHeaders(headers http.Header) map[string][]string { | |
| filtered := make(map[string][]string) | |
| for key, values := range headers { | |
| lowerKey := strings.ToLower(key) | |
| // Filter out sensitive headers | |
| if strings.Contains(lowerKey, "authorization") || | |
| strings.Contains(lowerKey, "api-key") || | |
| strings.Contains(lowerKey, "token") || | |
| strings.Contains(lowerKey, "secret") { | |
| filtered[key] = []string{"[REDACTED]"} | |
| } else { | |
| filtered[key] = values | |
| } | |
| } | |
| return filtered | |
| } | |
| func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) { | |
| if b == nil || b == http.NoBody { | |
| return http.NoBody, http.NoBody, nil | |
| } | |
| var buf bytes.Buffer | |
| if _, err = buf.ReadFrom(b); err != nil { | |
| return nil, b, err | |
| } | |
| if err = b.Close(); err != nil { | |
| return nil, b, err | |
| } | |
| return io.NopCloser(&buf), io.NopCloser(bytes.NewReader(buf.Bytes())), nil | |
| } | |