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