github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/api/cloudcontroller/wrapper/request_logger.go (about) 1 package wrapper 2 3 import ( 4 "io/ioutil" 5 "net/http" 6 "sort" 7 "strings" 8 "time" 9 10 "code.cloudfoundry.org/cli/api/cloudcontroller" 11 ) 12 13 //go:generate counterfeiter . RequestLoggerOutput 14 15 // RequestLoggerOutput is the interface for displaying logs 16 type RequestLoggerOutput interface { 17 DisplayJSONBody(body []byte) error 18 DisplayHeader(name string, value string) error 19 DisplayHost(name string) error 20 DisplayRequestHeader(method string, uri string, httpProtocol string) error 21 DisplayResponseHeader(httpProtocol string, status string) error 22 DisplayType(name string, requestDate time.Time) error 23 HandleInternalError(err error) 24 Start() error 25 Stop() error 26 } 27 28 // RequestLogger is the wrapper that logs requests to and responses from the 29 // Cloud Controller server 30 type RequestLogger struct { 31 connection cloudcontroller.Connection 32 output RequestLoggerOutput 33 } 34 35 // NewRequestLogger returns a pointer to a RequestLogger wrapper 36 func NewRequestLogger(output RequestLoggerOutput) *RequestLogger { 37 return &RequestLogger{ 38 output: output, 39 } 40 } 41 42 // Wrap sets the connection on the RequestLogger and returns itself 43 func (logger *RequestLogger) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection { 44 logger.connection = innerconnection 45 return logger 46 } 47 48 // Make records the request and the response to UI 49 func (logger *RequestLogger) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error { 50 err := logger.displayRequest(request) 51 if err != nil { 52 logger.output.HandleInternalError(err) 53 } 54 55 err = logger.connection.Make(request, passedResponse) 56 57 if passedResponse.HTTPResponse != nil { 58 displayErr := logger.displayResponse(passedResponse) 59 if displayErr != nil { 60 logger.output.HandleInternalError(displayErr) 61 } 62 } 63 64 return err 65 } 66 67 func (logger *RequestLogger) displayRequest(request *cloudcontroller.Request) error { 68 err := logger.output.Start() 69 if err != nil { 70 return err 71 } 72 defer logger.output.Stop() 73 74 err = logger.output.DisplayType("REQUEST", time.Now()) 75 if err != nil { 76 return err 77 } 78 err = logger.output.DisplayRequestHeader(request.Method, request.URL.RequestURI(), request.Proto) 79 if err != nil { 80 return err 81 } 82 err = logger.output.DisplayHost(request.URL.Host) 83 if err != nil { 84 return err 85 } 86 err = logger.displaySortedHeaders(request.Header) 87 if err != nil { 88 return err 89 } 90 91 if request.Body != nil && strings.Contains(request.Header.Get("Content-Type"), "json") { 92 rawRequestBody, err := ioutil.ReadAll(request.Body) 93 if err != nil { 94 return err 95 } 96 97 defer request.ResetBody() 98 99 err = logger.output.DisplayJSONBody(rawRequestBody) 100 if err != nil { 101 return err 102 } 103 } 104 105 return nil 106 } 107 108 func (logger *RequestLogger) displayResponse(passedResponse *cloudcontroller.Response) error { 109 err := logger.output.Start() 110 if err != nil { 111 return err 112 } 113 defer logger.output.Stop() 114 115 err = logger.output.DisplayType("RESPONSE", time.Now()) 116 if err != nil { 117 return err 118 } 119 err = logger.output.DisplayResponseHeader(passedResponse.HTTPResponse.Proto, passedResponse.HTTPResponse.Status) 120 if err != nil { 121 return err 122 } 123 err = logger.displaySortedHeaders(passedResponse.HTTPResponse.Header) 124 if err != nil { 125 return err 126 } 127 return logger.output.DisplayJSONBody(passedResponse.RawResponse) 128 } 129 130 func (logger *RequestLogger) displaySortedHeaders(headers http.Header) error { 131 keys := []string{} 132 for key, _ := range headers { 133 keys = append(keys, key) 134 } 135 sort.Strings(keys) 136 137 for _, key := range keys { 138 for _, value := range headers[key] { 139 err := logger.output.DisplayHeader(key, redactHeaders(key, value)) 140 if err != nil { 141 return err 142 } 143 } 144 } 145 return nil 146 } 147 148 func redactHeaders(key string, value string) string { 149 if key == "Authorization" { 150 return "[PRIVATE DATA HIDDEN]" 151 } 152 return value 153 }