Repository: helm/helm
File: pkg/registry/transport.go (Go)

Code before:
	// try to copy (clone) the http.DefaultTransport so any mutations we
	// perform on it (e.g. TLS config) are not reflected globally
	// follow https://github.com/golang/go/issues/39299 for a more elegant
	// solution in the future
	transport := http.DefaultTransport
	if t, ok := transport.(cloner[*http.Transport]); ok {
		transport = t.Clone()
	} else if t, ok := transport.(cloner[http.RoundTripper]); ok {
		// this branch will not be used with go 1.20, it was added
		// optimistically to try to clone if the http.DefaultTransport
		// implementation changes, still the Clone method in that case
		// might not return http.RoundTripper...
		transport = t.Clone()
	}
	if debug {
		replace := func(groups []string, a slog.Attr) slog.Attr {
			// Remove time.
			if a.Key == slog.TimeKey && len(groups) == 0 {
				return slog.Attr{}
			}
			return a
		}
		logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
			ReplaceAttr: replace,
			Level:       slog.LevelDebug}))
		slog.SetDefault(logger)
		transport = &LoggingTransport{RoundTripper: transport}
	}

	return retry.NewTransport(transport)
}

// RoundTrip calls base round trip while keeping track of the current request.
func (t *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	id := atomic.AddUint64(&requestCount, 1) - 1

	slog.Debug("Request", "id", id, "url", req.URL, "method", req.Method, "header", logHeader(req.Header))
	resp, err = t.RoundTripper.RoundTrip(req)
	if err != nil {
		slog.Debug("Response", "id", id, "error", err)
	} else if resp != nil {
		slog.Debug("Response", "id", id, "status", resp.Status, "header", logHeader(resp.Header), "body", logResponseBody(resp))
	} else {
		slog.Debug("Response", "id", id, "response", "nil")
	}

	return resp, err
}

// logHeader prints out the provided header keys and values, with auth header scrubbed.
func logHeader(header http.Header) string {

Review comment (suggestion):
`slog.SetDefault` is going to replace the system wide logger with this one. If an application is using the default logger or has set their own for `slog` and uses the Helm SDK, this is going to step on their logger.

Helm shouldn't step on the app wide logger.

Code after:

	// try to copy (clone) the http.DefaultTransport so any mutations we
	// perform on it (e.g. TLS config) are not reflected globally
	// follow https://github.com/golang/go/issues/39299 for a more elegant
	// solution in the future
	transport := http.DefaultTransport
	if t, ok := transport.(cloner[*http.Transport]); ok {
		transport = t.Clone()
	} else if t, ok := transport.(cloner[http.RoundTripper]); ok {
		// this branch will not be used with go 1.20, it was added
		// optimistically to try to clone if the http.DefaultTransport
		// implementation changes, still the Clone method in that case
		// might not return http.RoundTripper...
		transport = t.Clone()
	}
	if debug {
		replace := func(groups []string, a slog.Attr) slog.Attr {
			// Remove time.
			if a.Key == slog.TimeKey && len(groups) == 0 {
				return slog.Attr{}
			}
			return a
		}
		logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
			ReplaceAttr: replace,
			Level:       slog.LevelDebug}))
		transport = &LoggingTransport{RoundTripper: transport, logger: logger}
	}

	return retry.NewTransport(transport)
}

// RoundTrip calls base round trip while keeping track of the current request.
func (t *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	id := atomic.AddUint64(&requestCount, 1) - 1

	t.logger.Debug("Request", "id", id, "url", req.URL, "method", req.Method, "header", logHeader(req.Header))
	resp, err = t.RoundTripper.RoundTrip(req)
	if err != nil {
		t.logger.Debug("Response", "id", id, "error", err)
	} else if resp != nil {
		t.logger.Debug("Response", "id", id, "status", resp.Status, "header", logHeader(resp.Header), "body", logResponseBody(resp))
	} else {
		t.logger.Debug("Response", "id", id, "response", "nil")
	}

	return resp, err
}

// logHeader prints out the provided header keys and values, with auth header scrubbed.
func logHeader(header http.Header) string {