package logging import ( "bytes" "encoding/json" "log" "net/http" "net/http/httputil" "strings" ) type transport struct { name string transport http.RoundTripper } func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { if IsDebugOrHigher() { reqData, err := httputil.DumpRequestOut(req, true) if err == nil { log.Printf("[DEBUG] "+logReqMsg, t.name, prettyPrintJsonLines(reqData)) } else { log.Printf("[ERROR] %s API Request error: %#v", t.name, err) } } resp, err := t.transport.RoundTrip(req) if err != nil { return resp, err } if IsDebugOrHigher() { respData, err := httputil.DumpResponse(resp, true) if err == nil { log.Printf("[DEBUG] "+logRespMsg, t.name, prettyPrintJsonLines(respData)) } else { log.Printf("[ERROR] %s API Response error: %#v", t.name, err) } } return resp, nil } func NewTransport(name string, t http.RoundTripper) *transport { return &transport{name, t} } // prettyPrintJsonLines iterates through a []byte line-by-line, // transforming any lines that are complete json into pretty-printed json. func prettyPrintJsonLines(b []byte) string { parts := strings.Split(string(b), "\n") for i, p := range parts { if b := []byte(p); json.Valid(b) { var out bytes.Buffer json.Indent(&out, b, "", " ") parts[i] = out.String() } } return strings.Join(parts, "\n") } const logReqMsg = `%s API Request Details: ---[ REQUEST ]--------------------------------------- %s -----------------------------------------------------` const logRespMsg = `%s API Response Details: ---[ RESPONSE ]-------------------------------------- %s -----------------------------------------------------`