api/api.go
func (a *API) apiCall(reqMethod string, reqPath string, data []byte) ([]byte, error) {
	reqURL := a.apiURL.String()

	if reqPath == "" {
		return nil, errors.New("Invalid URL path")
	}
	if reqPath[:1] != "/" {
		reqURL += "/"
	}
	if len(reqPath) >= 3 && reqPath[:3] == "/v2" {
		reqURL += reqPath[3:]
	} else {
		reqURL += reqPath
	}

	// keep last HTTP error in the event of retry failure
	var lastHTTPError error
	retryPolicy := func(ctx context.Context, resp *http.Response, err error) (bool, error) {
		if ctxErr := ctx.Err(); ctxErr != nil {
			return false, ctxErr
		}

		if err != nil {
			lastHTTPError = err
			return true, err
		}
		// Check the response code. We retry on 500-range responses to allow
		// the server time to recover, as 500's are typically not permanent
		// errors and may relate to outages on the server side. This will catch
		// invalid response codes as well, like 0 and 999.
		// Retry on 429 (rate limit) as well.
		if resp.StatusCode == 0 || // wtf?!
			resp.StatusCode >= 500 || // rutroh
			resp.StatusCode == 429 { // rate limit
			body, readErr := ioutil.ReadAll(resp.Body)
			if readErr != nil {
				lastHTTPError = fmt.Errorf("- response: %d %s", resp.StatusCode, readErr.Error())
			} else {
				lastHTTPError = fmt.Errorf("- response: %d %s", resp.StatusCode, strings.TrimSpace(string(body)))
			}
			return true, nil
		}
		return false, nil
	}

	dataReader := bytes.NewReader(data)

	req, err := retryablehttp.NewRequest(reqMethod, reqURL, dataReader)
	if err != nil {
		return nil, fmt.Errorf("[ERROR] creating API request: %s %+v", reqURL, err)
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("X-Circonus-Auth-Token", string(a.key))
	req.Header.Add("X-Circonus-App-Name", string(a.app))
	if string(a.accountID) != "" {
		req.Header.Add("X-Circonus-Account-ID", string(a.accountID))
	}

	client := retryablehttp.NewClient()
	if a.apiURL.Scheme == "https" {
		var tlscfg *tls.Config
		if a.tlsConfig != nil { // preference full custom tls config
			tlscfg = a.tlsConfig
		} else if a.caCert != nil {
			tlscfg = &tls.Config{RootCAs: a.caCert}
		}
		client.HTTPClient.Transport = &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
			TLSClientConfig:     tlscfg,
			DisableKeepAlives:   true,
			MaxIdleConnsPerHost: -1,
			DisableCompression:  true,
		}
	} else {
		client.HTTPClient.Transport = &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
			DisableKeepAlives:   true,
			MaxIdleConnsPerHost: -1,
			DisableCompression:  true,
		}
	}

	a.useExponentialBackoffmu.Lock()
	eb := a.useExponentialBackoff
	a.useExponentialBackoffmu.Unlock()

	if eb {
		// limit to one request if using exponential backoff
		client.RetryWaitMin = 1
		client.RetryWaitMax = 2
		client.RetryMax = 0
	} else {
		client.RetryWaitMin = minRetryWait
		client.RetryWaitMax = maxRetryWait
		client.RetryMax = maxRetries
	}

	// retryablehttp only groks log or no log
	if a.Debug {
		client.Logger = a.Log
	} else {
		client.Logger = log.New(ioutil.Discard, "", log.LstdFlags)
	}

	client.CheckRetry = retryPolicy

	resp, err := client.Do(req)
	if err != nil {
		if lastHTTPError != nil {
			return nil, lastHTTPError
		}
		return nil, fmt.Errorf("[ERROR] %s: %+v", reqURL, err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[ERROR] reading response %+v", err)
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		msg := fmt.Sprintf("API response code %d: %s", resp.StatusCode, string(body))
		if a.Debug {
			a.Log.Printf("[DEBUG] %s\n", msg)
		}

		return nil, fmt.Errorf("[ERROR] %s", msg)
	}

	return body, nil
}
func (a *API) apiCall(reqMethod string, reqPath string, data []byte) ([]byte, error) {
	reqURL := a.apiURL.String()

	if reqPath == "" {
		return nil, errors.New("Invalid URL path")
	}
	if reqPath[:1] != "/" {
		reqURL += "/"
	}
	if len(reqPath) >= 3 && reqPath[:3] == "/v2" {
		reqURL += reqPath[3:]
	} else {
		reqURL += reqPath
	}

	// keep last HTTP error in the event of retry failure
	var lastHTTPError error
	retryPolicy := func(ctx context.Context, resp *http.Response, err error) (bool, error) {
		if ctxErr := ctx.Err(); ctxErr != nil {
			return false, ctxErr
		}

		if err != nil {
			lastHTTPError = err
			return true, err
		}
		// Check the response code. We retry on 500-range responses to allow
		// the server time to recover, as 500's are typically not permanent
		// errors and may relate to outages on the server side. This will catch
		// invalid response codes as well, like 0 and 999.
		// Retry on 429 (rate limit) as well.
		if resp.StatusCode == 0 || // wtf?!
			resp.StatusCode >= 500 || // rutroh
			resp.StatusCode == 429 { // rate limit
			body, readErr := ioutil.ReadAll(resp.Body)
			if readErr != nil {
				lastHTTPError = fmt.Errorf("- response: %d %s", resp.StatusCode, readErr.Error())
			} else {
				lastHTTPError = fmt.Errorf("- response: %d %s", resp.StatusCode, strings.TrimSpace(string(body)))
			}
			return true, nil
		}
		return false, nil
	}

	dataReader := bytes.NewReader(data)

	req, err := retryablehttp.NewRequest(reqMethod, reqURL, dataReader)
	if err != nil {
		return nil, fmt.Errorf("[ERROR] creating API request: %s %+v", reqURL, err)
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("X-Circonus-Auth-Token", string(a.key))
	req.Header.Add("X-Circonus-App-Name", string(a.app))
	if string(a.accountID) != "" {
		req.Header.Add("X-Circonus-Account-ID", string(a.accountID))
	}

	client := retryablehttp.NewClient()
	if a.apiURL.Scheme == "https" {
		var tlscfg *tls.Config
		if a.tlsConfig != nil { // preference full custom tls config
			tlscfg = a.tlsConfig
		} else if a.caCert != nil {
			tlscfg = &tls.Config{RootCAs: a.caCert}
		}
		client.HTTPClient.Transport = &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
			TLSClientConfig:     tlscfg,
			DisableKeepAlives:   true,
			MaxIdleConnsPerHost: -1,
			DisableCompression:  true,
		}
	} else {
		client.HTTPClient.Transport = &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
			DisableKeepAlives:   true,
			MaxIdleConnsPerHost: -1,
			DisableCompression:  true,
		}
	}

	a.useExponentialBackoffmu.Lock()
	eb := a.useExponentialBackoff
	a.useExponentialBackoffmu.Unlock()

	if eb {
		// limit to one request if using exponential backoff
		client.RetryWaitMin = 1
		client.RetryWaitMax = 2
		client.RetryMax = 0
	} else {
		client.RetryWaitMin = minRetryWait
		client.RetryWaitMax = maxRetryWait
		client.RetryMax = maxRetries
	}

	// retryablehttp only groks log or no log
	if a.Debug {
		client.Logger = a.Log
	} else {
		client.Logger = log.New(ioutil.Discard, "", log.LstdFlags)
	}

	client.CheckRetry = retryPolicy

	resp, err := client.Do(req)
	if err != nil {
		if lastHTTPError != nil {
			return nil, lastHTTPError
		}
		return nil, fmt.Errorf("[ERROR] %s: %+v", reqURL, err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[ERROR] reading response %+v", err)
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		msg := fmt.Sprintf("API response code %d: %s", resp.StatusCode, string(body))
		if a.Debug {
			a.Log.Printf("[DEBUG] %s\n", msg)
		}

		return nil, fmt.Errorf("[ERROR] %s", msg)
	}

	return body, nil
}
func ( a * API ) apiCall ( reqMethod string , reqPath string , data [ ] byte ) ( [ ] byte , error ) { reqURL := a . apiURL . String ( ) if reqPath == " " { return nil , errors . New ( " " ) } if reqPath [ : 1 ] != " " { reqURL += " " } if len ( reqPath ) >= 3 && reqPath [ : 3 ] == " " { reqURL += reqPath [ 3 : ] } else { reqURL += reqPath } // keep last HTTP error in the event of retry failure var lastHTTPError error retryPolicy := func ( ctx context . Context , resp * http . Response , err error ) ( bool , error ) { if ctxErr := ctx . Err ( ) ; ctxErr != nil { return false , ctxErr } if err != nil { lastHTTPError = err return true , err } // Check the response code. We retry on 500-range responses to allow // the server time to recover, as 500's are typically not permanent // errors and may relate to outages on the server side. This will catch // invalid response codes as well, like 0 and 999. // Retry on 429 (rate limit) as well. if resp . StatusCode == 0 || // wtf?! resp . StatusCode >= 500 || // rutroh resp . StatusCode == 429 { // rate limit body , readErr := ioutil . ReadAll ( resp . Body ) if readErr != nil { lastHTTPError = fmt . Errorf ( " " , resp . StatusCode , readErr . Error ( ) ) } else { lastHTTPError = fmt . Errorf ( " " , resp . StatusCode , strings . TrimSpace ( string ( body ) ) ) } return true , nil } return false , nil } dataReader := bytes . NewReader ( data ) req , err := retryablehttp . NewRequest ( reqMethod , reqURL , dataReader ) if err != nil { return nil , fmt . Errorf ( " " , reqURL , err ) } req . Header . Add ( " " , " " ) req . Header . Add ( " " , string ( a . key ) ) req . Header . Add ( " " , string ( a . app ) ) if string ( a . accountID ) != " " { req . Header . Add ( " " , string ( a . accountID ) ) } client := retryablehttp . NewClient ( ) if a . apiURL . Scheme == " " { var tlscfg * tls . Config if a . tlsConfig != nil { // preference full custom tls config tlscfg = a . tlsConfig } else if a . caCert != nil { tlscfg = & tls . Config { RootCAs : a . caCert } } client . HTTPClient . Transport = & http . Transport { Proxy : http . ProxyFromEnvironment , Dial : ( & net . Dialer { Timeout : 30 * time . Second , KeepAlive : 30 * time . Second , } ) . Dial , TLSHandshakeTimeout : 10 * time . Second , TLSClientConfig : tlscfg , DisableKeepAlives : true , MaxIdleConnsPerHost : - 1 , DisableCompression : true , } } else { client . HTTPClient . Transport = & http . Transport { Proxy : http . ProxyFromEnvironment , Dial : ( & net . Dialer { Timeout : 30 * time . Second , KeepAlive : 30 * time . Second , } ) . Dial , TLSHandshakeTimeout : 10 * time . Second , DisableKeepAlives : true , MaxIdleConnsPerHost : - 1 , DisableCompression : true , } } a . useExponentialBackoffmu . Lock ( ) eb := a . useExponentialBackoff a . useExponentialBackoffmu . Unlock ( ) if eb { // limit to one request if using exponential backoff client . RetryWaitMin = 1 client . RetryWaitMax = 2 client . RetryMax = 0 } else { client . RetryWaitMin = minRetryWait client . RetryWaitMax = maxRetryWait client . RetryMax = maxRetries } // retryablehttp only groks log or no log if a . Debug { client . Logger = a . Log } else { client . Logger = log . New ( ioutil . Discard , " " , log . LstdFlags ) } client . CheckRetry = retryPolicy resp , err := client . Do ( req ) if err != nil { if lastHTTPError != nil { return nil , lastHTTPError } return nil , fmt . Errorf ( " " , reqURL , err ) } defer resp . Body . Close ( ) body , err := ioutil . ReadAll ( resp . Body ) if err != nil { return nil , fmt . Errorf ( " " , err ) } if resp . StatusCode < 200 || resp . StatusCode >= 300 { msg := fmt . Sprintf ( " " , resp . StatusCode , string ( body ) ) if a . Debug { a . Log . Printf ( " \n " , msg ) } return nil , fmt . Errorf ( " " , msg ) } return body , nil }
// apiCall call Circonus API
apiCall call Circonus API