diff --git a/.gitignore b/.gitignore index 0fad266..d5e42a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store debug.test +.idea diff --git a/docs/README.md b/docs/README.md index cbceddd..ee5d925 100644 --- a/docs/README.md +++ b/docs/README.md @@ -234,3 +234,36 @@ client.SetUserAgent("your-user-agent-value") // send API request... ``` + +# Logging + +## Adding a custom logger + +You can add a custom logger to the client that will be used to print outgoing requests and incoming responses. Debug +mode must be set to `true` to enable logging. + +This is an example of how to enable logging and log to a file: + +```go +// Create a logger, which outputs to file. +f, err := os.OpenFile("log.txt", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666) +if err != nil { + log.Fatalf("error opening file: %v", err) +} +defer f.Close() + +fileLogger := &log.Logger{} +fileLogger.SetOutput(f) + +client, err := helix.NewClient(&helix.Options{ + logger: fileLogger, + debug: true, +}) +if err != nil { + log.Fatalf("error opening file: %v", err) + +} +``` + +Should you want to enable debug mode but not want to use a custom logger, stdout will be used as the default log output. + diff --git a/helix.go b/helix.go index 16ea873..7a49f6f 100644 --- a/helix.go +++ b/helix.go @@ -5,7 +5,9 @@ import ( "errors" "fmt" "io/ioutil" + "log" "net/http" + "net/http/httputil" "reflect" "strconv" "strings" @@ -39,6 +41,10 @@ type Client struct { baseURL string lastResponse *Response + + // Logging + debug bool + logger *log.Logger } // Options ... @@ -52,6 +58,8 @@ type Options struct { Scopes []string HTTPClient HTTPClient RateLimitFunc RateLimitFunc + Debug bool + Logger *log.Logger } // RateLimitFunc ... @@ -108,9 +116,17 @@ func NewClient(options *Options) (*Client, error) { c := &Client{ clientID: options.ClientID, httpClient: http.DefaultClient, + logger: options.Logger, + debug: options.Debug, } // Set options + + // Use the default logger, if none was set by the user. + if options.Logger == nil { + c.logger = log.New(os.Stdout, "Helix: ", log.LstdFlags) + } + if options.HTTPClient != nil { c.httpClient = options.HTTPClient } @@ -151,11 +167,19 @@ func (c *Client) sendRequest(method, path string, respData, reqData interface{}) return nil, err } + if c.debug { + c.logger.Printf("%+v\n", req) + } + err = c.doRequest(req, resp) if err != nil { return nil, err } + if c.debug { + c.logger.Printf("%+v\n", resp) + } + return resp, nil } @@ -279,12 +303,30 @@ func (c *Client) doRequest(req *http.Request, resp *Response) error { } } + // Dump request on debug. + if c.debug { + bodyBytes, err := httputil.DumpRequest(req, true) + if err != nil { + return fmt.Errorf("Failed to dump API request: %s", err.Error()) + } + c.logger.Println(string(bodyBytes)) + } + response, err := c.httpClient.Do(req) if err != nil { return fmt.Errorf("Failed to execute API request: %s", err.Error()) } defer response.Body.Close() + // Dump response on debug. + if c.debug { + bodyBytes, err := httputil.DumpResponse(response, true) + if err != nil { + return fmt.Errorf("Failed to dump API response: %s", err.Error()) + } + c.logger.Println(string(bodyBytes)) + } + resp.Header = response.Header setResponseStatusCode(resp, "StatusCode", response.StatusCode)