diff --git a/client.go b/client.go index c0f60b0..ef31aab 100644 --- a/client.go +++ b/client.go @@ -277,6 +277,15 @@ type Logger interface { Printf(string, ...interface{}) } +// LeveledFormatLogger interface allows to use logger libraries that use formatted +// leveled methods for loging +type LeveledFormatLogger interface { + Infof(string, ...interface{}) + Debugf(string, ...interface{}) + Warnf(string, ...interface{}) + Errorf(string, ...interface{}) +} + // LeveledLogger is an interface that can be implemented by any logger or a // logger wrapper to provide leveled logging. The methods accept a message // string and a variadic number of key-value pairs. For log.Printf style @@ -299,6 +308,16 @@ func (h hookLogger) Printf(s string, args ...interface{}) { h.Info(fmt.Sprintf(s, args...)) } +// hookFormatLogger adapts an LeveledFormatLogger to Logger for use by the existing hook +// functions without changing the API. +type hookFormatLogger struct { + LeveledFormatLogger +} + +func (h hookFormatLogger) Printf(s string, args ...interface{}) { + h.Infof(fmt.Sprintf(s, args...)) +} + // RequestLogHook allows a function to run before each retry. The HTTP // request which will be made, and the retry number (0 for the initial // request) are available to users. The internal logger is exposed to @@ -385,11 +404,11 @@ func (c *Client) logger() interface{} { } switch c.Logger.(type) { - case Logger, LeveledLogger: + case Logger, LeveledLogger, LeveledFormatLogger: // ok default: // This should happen in dev when they are setting Logger and work on code, not in prod. - panic(fmt.Sprintf("invalid logger type passed, must be Logger or LeveledLogger, was %T", c.Logger)) + panic(fmt.Sprintf("invalid logger type passed, must be Logger, LeveledLogger or LeveledFormatLogger, was %T", c.Logger)) } }) @@ -569,6 +588,8 @@ func (c *Client) Do(req *Request) (*http.Response, error) { if logger != nil { switch v := logger.(type) { + case LeveledFormatLogger: + v.Debugf("%s %s: performing request", req.Method, req.URL) case LeveledLogger: v.Debug("performing request", "method", req.Method, "url", req.URL) case Logger: @@ -602,6 +623,8 @@ func (c *Client) Do(req *Request) (*http.Response, error) { if c.RequestLogHook != nil { switch v := logger.(type) { + case LeveledFormatLogger: + c.RequestLogHook(hookFormatLogger{v}, req.Request, i) case LeveledLogger: c.RequestLogHook(hookLogger{v}, req.Request, i) case Logger: @@ -622,6 +645,8 @@ func (c *Client) Do(req *Request) (*http.Response, error) { if doErr != nil { switch v := logger.(type) { + case LeveledFormatLogger: + v.Errorf("%s %s: request failed: %s", req.Method, req.URL, doErr) case LeveledLogger: v.Error("request failed", "error", doErr, "method", req.Method, "url", req.URL) case Logger: @@ -633,6 +658,8 @@ func (c *Client) Do(req *Request) (*http.Response, error) { if c.ResponseLogHook != nil { // Call the response logger function if provided. switch v := logger.(type) { + case LeveledFormatLogger: + c.ResponseLogHook(hookFormatLogger{v}, resp) case LeveledLogger: c.ResponseLogHook(hookLogger{v}, resp) case Logger: @@ -666,6 +693,8 @@ func (c *Client) Do(req *Request) (*http.Response, error) { } if logger != nil { switch v := logger.(type) { + case LeveledFormatLogger: + v.Debugf("%s: retrying request in %s (%d left)", desc, wait, remain) case LeveledLogger: v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain) case Logger: @@ -720,6 +749,8 @@ func (c *Client) drainBody(body io.ReadCloser) { if err != nil { if c.logger() != nil { switch v := c.logger().(type) { + case LeveledFormatLogger: + v.Errorf("error reading response body: %s", err) case LeveledLogger: v.Error("error reading response body", "error", err) case Logger: