github.com/anthropics/anthropic-sdk-go@v1.70.1/option/middleware.go (about)

     1  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
     2  
     3  package option
     4  
     5  import (
     6  	"log"
     7  	"net/http"
     8  	"net/http/httputil"
     9  )
    10  
    11  // sensitiveLogHeaders are redacted before request and response content is
    12  // written to the debug logger.
    13  var sensitiveLogHeaders = []string{"authorization", "api-key", "x-api-key", "cookie", "set-cookie"}
    14  
    15  // WithDebugLog logs the HTTP request and response content.
    16  // If the logger parameter is nil, it uses the default logger.
    17  //
    18  // WithDebugLog is for debugging and development purposes only.
    19  // It should not be used in production code. The behavior and interface
    20  // of WithDebugLog is not guaranteed to be stable.
    21  func WithDebugLog(logger *log.Logger) RequestOption {
    22  	return WithMiddleware(func(req *http.Request, nxt MiddlewareNext) (*http.Response, error) {
    23  		if logger == nil {
    24  			logger = log.Default()
    25  		}
    26  
    27  		if reqBytes, err := dumpRedactedRequest(req); err == nil {
    28  			logger.Printf("Request Content:\n%s\n", reqBytes)
    29  		}
    30  
    31  		resp, err := nxt(req)
    32  		if err != nil {
    33  			return resp, err
    34  		}
    35  
    36  		if respBytes, err := dumpRedactedResponse(resp); err == nil {
    37  			logger.Printf("Response Content:\n%s\n", respBytes)
    38  		}
    39  
    40  		return resp, err
    41  	})
    42  }
    43  
    44  // dumpRedactedRequest dumps req with sensitive headers replaced. The
    45  // original headers are restored via defer so a panic in DumpRequest cannot
    46  // leak the placeholder map into the live request sent downstream.
    47  func dumpRedactedRequest(req *http.Request) ([]byte, error) {
    48  	origHeaders := req.Header
    49  	req.Header = redactDebugHeaders(origHeaders)
    50  	defer func() { req.Header = origHeaders }()
    51  	return httputil.DumpRequest(req, true)
    52  }
    53  
    54  func dumpRedactedResponse(resp *http.Response) ([]byte, error) {
    55  	origHeaders := resp.Header
    56  	resp.Header = redactDebugHeaders(origHeaders)
    57  	defer func() { resp.Header = origHeaders }()
    58  	return httputil.DumpResponse(resp, true)
    59  }
    60  
    61  func redactDebugHeaders(headers http.Header) http.Header {
    62  	var redacted http.Header
    63  	for _, name := range sensitiveLogHeaders {
    64  		values := headers.Values(name)
    65  		if len(values) == 0 {
    66  			continue
    67  		}
    68  		if redacted == nil {
    69  			redacted = headers.Clone()
    70  		}
    71  		redacted.Del(name)
    72  		for range values {
    73  			redacted.Add(name, "***")
    74  		}
    75  	}
    76  	if redacted == nil {
    77  		return headers
    78  	}
    79  	return redacted
    80  }