Skip to content

Commit

Permalink
feat: Adding github rate limit metrics exposure
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Boutour <[email protected]>
  • Loading branch information
ViBiOh committed Mar 25, 2021
1 parent cb5148d commit bec6103
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
4 changes: 3 additions & 1 deletion cmd/ketchup/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func main() {
authServiceApp, authMiddlewareApp := initAuth(ketchupDb)

userServiceApp := userService.New(userStore.New(ketchupDb), authServiceApp)
repositoryServiceApp := repositoryService.New(repositoryStore.New(ketchupDb), github.New(githubConfig), helm.New())
githubApp := github.New(githubConfig)
repositoryServiceApp := repositoryService.New(repositoryStore.New(ketchupDb), githubApp, helm.New())
ketchupServiceApp := ketchupService.New(ketchupStore.New(ketchupDb), repositoryServiceApp)

mailerApp, err := mailer.New(mailerConfig)
Expand Down Expand Up @@ -129,6 +130,7 @@ func main() {
})

go ketchupApp.Start(healthApp.Done())
go githubApp.Start(prometheusApp.Registerer(), healthApp.Done())
if schedulerApp != nil {
go schedulerApp.Start(healthApp.Done())
}
Expand Down
56 changes: 54 additions & 2 deletions pkg/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"strings"
"time"

"github.com/ViBiOh/httputils/v4/pkg/cron"
"github.com/ViBiOh/httputils/v4/pkg/flags"
"github.com/ViBiOh/httputils/v4/pkg/logger"
"github.com/ViBiOh/httputils/v4/pkg/request"
"github.com/ViBiOh/ketchup/pkg/model"
"github.com/ViBiOh/ketchup/pkg/semver"
"github.com/prometheus/client_golang/prometheus"
)

var (
Expand All @@ -25,8 +27,19 @@ type Tag struct {
Name string `json:"name"`
}

// RateLimit describes a rate limit on given ressource
type RateLimit struct {
Remaining uint64 `json:"remaining"`
}

// RateLimitResponse describes the rate_limit response
type RateLimitResponse struct {
Resources map[string]RateLimit `json:"resources"`
}

// App of package
type App interface {
Start(prometheus.Registerer, <-chan struct{})
LatestVersions(string, []string) (map[string]semver.Version, error)
}

Expand Down Expand Up @@ -63,6 +76,26 @@ func (a app) newClient() *request.Request {
})
}

func (a app) Start(registerer prometheus.Registerer, done <-chan struct{}) {
metrics := prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: "ketchup",
Name: "github_rate_limit_remainings",
})
registerer.MustRegister(metrics)

cron.New().Now().Each(time.Minute).OnError(func(err error) {
logger.Error("unable to get rate limit metrics: %s", err)
}).Start(func(_ time.Time) error {
value, err := a.getRateLimit()
if err != nil {
return err
}

metrics.Set(float64(value))
return nil
}, done)
}

func (a app) LatestVersions(repository string, patterns []string) (map[string]semver.Version, error) {
versions, compiledPatterns, err := model.PreparePatternMatching(patterns)
if err != nil {
Expand All @@ -79,12 +112,12 @@ func (a app) LatestVersions(repository string, patterns []string) (map[string]se

payload, err := request.ReadBodyResponse(resp)
if err != nil {
return nil, fmt.Errorf("unable to read page %d tags body `%s`: %s", page, payload, err)
return nil, fmt.Errorf("unable to read page %d tags body: %s", page, err)
}

var tags []Tag
if err := json.Unmarshal(payload, &tags); err != nil {
return nil, fmt.Errorf("unable to parse page %d tags body: %s", page, err)
return nil, fmt.Errorf("unable to parse page %d tags body `%s`: %s", page, payload, err)
}

for _, tag := range tags {
Expand All @@ -106,6 +139,25 @@ func (a app) LatestVersions(repository string, patterns []string) (map[string]se
return versions, nil
}

func (a app) getRateLimit() (uint64, error) {
resp, err := a.newClient().Get(fmt.Sprintf("%s/rate_limit", apiURL)).Send(context.Background(), nil)
if err != nil {
return 0, fmt.Errorf("unable to get rate limit: %s", err)
}

payload, err := request.ReadBodyResponse(resp)
if err != nil {
return 0, fmt.Errorf("unable to read rate limit body `%s`: %s", payload, err)
}

var rateLimits RateLimitResponse
if err := json.Unmarshal(payload, &rateLimits); err != nil {
return 0, fmt.Errorf("unable to parse rate limit response body `%s`: %s", payload, err)
}

return rateLimits.Resources["core"].Remaining, nil
}

func hasNext(resp *http.Response) bool {
for _, value := range resp.Header.Values("Link") {
if strings.Contains(value, `rel="next"`) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/github/githubtest/githubtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package githubtest
import (
"github.com/ViBiOh/ketchup/pkg/github"
"github.com/ViBiOh/ketchup/pkg/semver"
"github.com/prometheus/client_golang/prometheus"
)

var _ github.App = &App{}
Expand Down Expand Up @@ -30,3 +31,7 @@ func (a *App) SetLatestVersions(latestVersions map[string]semver.Version, err er
func (a App) LatestVersions(_ string, _ []string) (map[string]semver.Version, error) {
return a.latestVersions, a.latestVersionsErr
}

// Start mock
func (a App) Start(_ prometheus.Registerer, _ <-chan struct{}) {
}

0 comments on commit bec6103

Please sign in to comment.