github.com/lukasheimann/cloudfoundrycli@v7.1.0+incompatible/command/log_cache_client.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "net" 6 "net/http" 7 "runtime" 8 "strings" 9 "time" 10 11 "code.cloudfoundry.org/cli/util" 12 logcache "code.cloudfoundry.org/go-log-cache" 13 ) 14 15 type RequestLoggerOutput interface { 16 Start() error 17 Stop() error 18 19 DisplayType(name string, requestDate time.Time) error 20 DisplayDump(dump string) error 21 22 DisplayHost(name string) error 23 DisplayRequestHeader(method string, uri string, httpProtocol string) error 24 DisplayResponseHeader(httpProtocol string, status string) error 25 } 26 27 type DebugPrinter struct { 28 outputs []RequestLoggerOutput 29 } 30 31 func (p DebugPrinter) PrintError(err error) { 32 for _, output := range p.outputs { 33 _ = output.Start() //nolint 34 _ = output.DisplayType("ERROR", time.Now()) //nolint 35 _ = output.DisplayDump(err.Error()) //nolint 36 _ = output.Stop() //nolint 37 } 38 } 39 40 func (p DebugPrinter) PrintRequest(req *http.Request) { 41 for _, output := range p.outputs { 42 _ = output.Start() //nolint 43 _ = output.DisplayType("REQUEST", time.Now()) //nolint 44 _ = output.DisplayRequestHeader(req.Method, req.URL.RequestURI(), req.Proto) //nolint 45 _ = output.DisplayHost(req.URL.Host) //nolint 46 _ = output.DisplayDump(headersString(req.Header)) //nolint 47 _ = output.Stop() //nolint 48 } 49 } 50 51 func (p DebugPrinter) PrintResponse(resp *http.Response) { 52 for _, output := range p.outputs { 53 _ = output.Start() //nolint 54 _ = output.DisplayType("RESPONSE", time.Now()) //nolint 55 _ = output.DisplayResponseHeader(resp.Proto, resp.Status) //nolint 56 _ = output.DisplayDump(headersString(resp.Header)) //nolint 57 _ = output.Stop() //nolint 58 } 59 } 60 61 func (p *DebugPrinter) addOutput(output RequestLoggerOutput) { 62 p.outputs = append(p.outputs, output) 63 } 64 65 type tokenHTTPClient struct { 66 c logcache.HTTPClient 67 accessToken func() string 68 userAgent string 69 } 70 71 func (c *tokenHTTPClient) Do(req *http.Request) (*http.Response, error) { 72 req.Header.Set("Authorization", c.accessToken()) 73 req.Header.Set("User-Agent", c.userAgent) 74 return c.c.Do(req) 75 } 76 77 type httpDebugClient struct { 78 printer DebugPrinter 79 c logcache.HTTPClient 80 } 81 82 func (c *httpDebugClient) Do(req *http.Request) (*http.Response, error) { 83 c.printer.PrintRequest(req) 84 85 resp, err := c.c.Do(req) 86 if err != nil { 87 c.printer.PrintError(err) 88 return nil, err 89 } 90 91 c.printer.PrintResponse(resp) 92 93 return resp, err 94 } 95 96 // NewLogCacheClient returns back a configured Log Cache Client. 97 func NewLogCacheClient(logCacheEndpoint string, config Config, ui UI) *logcache.Client { 98 tr := &http.Transport{ 99 Proxy: http.ProxyFromEnvironment, 100 TLSClientConfig: util.NewTLSConfig(nil, config.SkipSSLValidation()), 101 DialContext: (&net.Dialer{ 102 KeepAlive: 30 * time.Second, 103 Timeout: config.DialTimeout(), 104 }).DialContext, 105 } 106 107 var client logcache.HTTPClient //nolint 108 client = &http.Client{Transport: tr} 109 110 verbose, location := config.Verbose() 111 if verbose && ui != nil { 112 printer := DebugPrinter{} 113 printer.addOutput(ui.RequestLoggerTerminalDisplay()) 114 if location != nil { 115 printer.addOutput(ui.RequestLoggerFileWriter(location)) 116 } 117 118 client = &httpDebugClient{printer: printer, c: client} 119 } 120 121 userAgent := fmt.Sprintf("%s/%s (%s; %s %s)", config.BinaryName(), config.BinaryVersion(), runtime.Version(), runtime.GOARCH, runtime.GOOS) 122 return logcache.NewClient( 123 logCacheEndpoint, 124 logcache.WithHTTPClient(&tokenHTTPClient{ 125 c: client, 126 accessToken: config.AccessToken, 127 userAgent: userAgent, 128 }), 129 ) 130 } 131 func headersString(header http.Header) string { 132 var result string 133 for name, values := range header { 134 result += name + ": " + strings.Join(values, ", ") + "\n" 135 } 136 return result 137 }