Add metrics for GitHub API rate limit (#312)
This commit is contained in:
		
							parent
							
								
									2623140c9a
								
							
						
					
					
						commit
						4f3f2fb60d
					
				|  | @ -11,6 +11,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/bradleyfalzon/ghinstallation" | 	"github.com/bradleyfalzon/ghinstallation" | ||||||
| 	"github.com/google/go-github/v33/github" | 	"github.com/google/go-github/v33/github" | ||||||
|  | 	"github.com/summerwind/actions-runner-controller/github/metrics" | ||||||
| 	"golang.org/x/oauth2" | 	"golang.org/x/oauth2" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -34,15 +35,9 @@ type Client struct { | ||||||
| 
 | 
 | ||||||
| // NewClient creates a Github Client
 | // NewClient creates a Github Client
 | ||||||
| func (c *Config) NewClient() (*Client, error) { | func (c *Config) NewClient() (*Client, error) { | ||||||
| 	var ( | 	var transport http.RoundTripper | ||||||
| 		httpClient *http.Client |  | ||||||
| 		client     *github.Client |  | ||||||
| 	) |  | ||||||
| 	githubBaseURL := "https://github.com/" |  | ||||||
| 	if len(c.Token) > 0 { | 	if len(c.Token) > 0 { | ||||||
| 		httpClient = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource( | 		transport = oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.Token})).Transport | ||||||
| 			&oauth2.Token{AccessToken: c.Token}, |  | ||||||
| 		)) |  | ||||||
| 	} else { | 	} else { | ||||||
| 		tr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, c.AppID, c.AppInstallationID, c.AppPrivateKey) | 		tr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, c.AppID, c.AppInstallationID, c.AppPrivateKey) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | @ -55,9 +50,13 @@ func (c *Config) NewClient() (*Client, error) { | ||||||
| 			} | 			} | ||||||
| 			tr.BaseURL = githubAPIURL | 			tr.BaseURL = githubAPIURL | ||||||
| 		} | 		} | ||||||
| 		httpClient = &http.Client{Transport: tr} | 		transport = tr | ||||||
| 	} | 	} | ||||||
|  | 	transport = metrics.Transport{Transport: transport} | ||||||
|  | 	httpClient := &http.Client{Transport: transport} | ||||||
| 
 | 
 | ||||||
|  | 	var client *github.Client | ||||||
|  | 	var githubBaseURL string | ||||||
| 	if len(c.EnterpriseURL) > 0 { | 	if len(c.EnterpriseURL) > 0 { | ||||||
| 		var err error | 		var err error | ||||||
| 		client, err = github.NewEnterpriseClient(c.EnterpriseURL, c.EnterpriseURL, httpClient) | 		client, err = github.NewEnterpriseClient(c.EnterpriseURL, c.EnterpriseURL, httpClient) | ||||||
|  | @ -67,6 +66,7 @@ func (c *Config) NewClient() (*Client, error) { | ||||||
| 		githubBaseURL = fmt.Sprintf("%s://%s%s", client.BaseURL.Scheme, client.BaseURL.Host, strings.TrimSuffix(client.BaseURL.Path, "api/v3/")) | 		githubBaseURL = fmt.Sprintf("%s://%s%s", client.BaseURL.Scheme, client.BaseURL.Host, strings.TrimSuffix(client.BaseURL.Path, "api/v3/")) | ||||||
| 	} else { | 	} else { | ||||||
| 		client = github.NewClient(httpClient) | 		client = github.NewClient(httpClient) | ||||||
|  | 		githubBaseURL = "https://github.com/" | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return &Client{ | 	return &Client{ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,63 @@ | ||||||
|  | // Package metrics provides monitoring of the GitHub related metrics.
 | ||||||
|  | //
 | ||||||
|  | // This depends on the metrics exporter of kubebuilder.
 | ||||||
|  | // See https://book.kubebuilder.io/reference/metrics.html for details.
 | ||||||
|  | package metrics | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"strconv" | ||||||
|  | 
 | ||||||
|  | 	"github.com/prometheus/client_golang/prometheus" | ||||||
|  | 	"sigs.k8s.io/controller-runtime/pkg/metrics" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	metrics.Registry.MustRegister(metricRateLimit, metricRateLimitRemaining) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
 | ||||||
|  | 	metricRateLimit = prometheus.NewGauge( | ||||||
|  | 		prometheus.GaugeOpts{ | ||||||
|  | 			Name: "github_rate_limit", | ||||||
|  | 			Help: "The maximum number of requests you're permitted to make per hour", | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | 	metricRateLimitRemaining = prometheus.NewGauge( | ||||||
|  | 		prometheus.GaugeOpts{ | ||||||
|  | 			Name: "github_rate_limit_remaining", | ||||||
|  | 			Help: "The number of requests remaining in the current rate limit window", | ||||||
|  | 		}, | ||||||
|  | 	) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting
 | ||||||
|  | 	headerRateLimit          = "X-RateLimit-Limit" | ||||||
|  | 	headerRateLimitRemaining = "X-RateLimit-Remaining" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Transport wraps a transport with metrics monitoring
 | ||||||
|  | type Transport struct { | ||||||
|  | 	Transport http.RoundTripper | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) { | ||||||
|  | 	resp, err := t.Transport.RoundTrip(req) | ||||||
|  | 	if resp != nil { | ||||||
|  | 		parseResponse(resp) | ||||||
|  | 	} | ||||||
|  | 	return resp, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func parseResponse(resp *http.Response) { | ||||||
|  | 	rateLimit, err := strconv.Atoi(resp.Header.Get(headerRateLimit)) | ||||||
|  | 	if err == nil { | ||||||
|  | 		metricRateLimit.Set(float64(rateLimit)) | ||||||
|  | 	} | ||||||
|  | 	rateLimitRemaining, err := strconv.Atoi(resp.Header.Get(headerRateLimitRemaining)) | ||||||
|  | 	if err == nil { | ||||||
|  | 		metricRateLimitRemaining.Set(float64(rateLimitRemaining)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										1
									
								
								go.mod
								
								
								
								
							|  | @ -11,6 +11,7 @@ require ( | ||||||
| 	github.com/kelseyhightower/envconfig v1.4.0 | 	github.com/kelseyhightower/envconfig v1.4.0 | ||||||
| 	github.com/onsi/ginkgo v1.8.0 | 	github.com/onsi/ginkgo v1.8.0 | ||||||
| 	github.com/onsi/gomega v1.5.0 | 	github.com/onsi/gomega v1.5.0 | ||||||
|  | 	github.com/prometheus/client_golang v0.9.2 | ||||||
| 	github.com/stretchr/testify v1.4.0 // indirect | 	github.com/stretchr/testify v1.4.0 // indirect | ||||||
| 	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 | 	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 | ||||||
| 	k8s.io/api v0.0.0-20190918155943-95b840bb6a1f | 	k8s.io/api v0.0.0-20190918155943-95b840bb6a1f | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue