github.com/orange-cloudfoundry/cli@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  }