Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ github_repo_open_issues{archived="false",fork="false",language="Go",license="mit
# HELP github_repo_pull_request_count Total number of pull requests for given repository
# TYPE github_repo_pull_request_count gauge
github_repo_pull_request_count{repo="github-exporter",user="githubexporter"} 7
# HELP github_repo_releases Total number of releases for given repository
# TYPE github_repo_releases gauge
github_repo_releases{repo="github-exporter",user="githubexporter"} 20
# HELP github_repo_size_kb Size in KB for given repository
# TYPE github_repo_size_kb gauge
github_repo_size_kb{archived="false",fork="false",language="Go",license="mit",private="false",repo="github-exporter",user="githubexporter"} 2185
Expand Down
11 changes: 11 additions & 0 deletions exporter/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func AddMetrics(cfg *config.Config) map[string]*prometheus.Desc {
"Size in KB for given repository",
[]string{"repo", "user", "private", "fork", "archived", "license", "language"}, nil,
)
APIMetrics["Releases"] = prometheus.NewDesc(
prometheus.BuildFQName("github", "repo", "releases"),
"Total number of releases for given repository",
[]string{"repo", "user"}, nil,
)
APIMetrics["ReleaseDownloads"] = prometheus.NewDesc(
prometheus.BuildFQName("github", "repo", "release_downloads"),
"Download count for a given release",
Expand Down Expand Up @@ -102,6 +107,12 @@ func (e *Exporter) processMetrics(data []*Datum, rates *[]RateLimit, ch chan<- p
ch <- prometheus.MustNewConstMetric(e.APIMetrics["Watchers"], prometheus.GaugeValue, float64(x.Watchers), x.Name, x.Owner.Login, strconv.FormatBool(x.Private), strconv.FormatBool(x.Fork), strconv.FormatBool(x.Archived), x.License.Key, x.Language)
ch <- prometheus.MustNewConstMetric(e.APIMetrics["Size"], prometheus.GaugeValue, float64(x.Size), x.Name, x.Owner.Login, strconv.FormatBool(x.Private), strconv.FormatBool(x.Fork), strconv.FormatBool(x.Archived), x.License.Key, x.Language)

// Only report a release count when releases were fetched, so a
// disabled fetch isn't reported as zero releases
if e.FetchRepoReleasesEnabled {
ch <- prometheus.MustNewConstMetric(e.APIMetrics["Releases"], prometheus.GaugeValue, float64(len(x.Releases)), x.Name, x.Owner.Login)
}

for _, release := range x.Releases {
for _, asset := range release.Assets {
ch <- prometheus.MustNewConstMetric(e.APIMetrics["ReleaseDownloads"], prometheus.GaugeValue, float64(asset.Downloads), x.Name, x.Owner.Login, release.Name, asset.Name, release.Tag, asset.CreatedAt)
Expand Down
39 changes: 39 additions & 0 deletions test/github_exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func TestGithubExporter(t *testing.T) {
Assert(bodyContains(`github_rate_reset{resource="search"} 3e+09`)).
Assert(bodyContains(`github_repo_forks{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myOrg"} 10`)).
Assert(bodyContains(`github_repo_pull_request_count{repo="myRepo",user="myOrg"} 3`)).
Assert(bodyContains(`github_repo_releases{repo="myRepo",user="myOrg"} 2`)).
Assert(bodyContains(`github_repo_open_issues{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myOrg"} 2`)).
Assert(bodyContains(`github_repo_size_kb{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myOrg"} 946`)).
Assert(bodyContains(`github_repo_stars{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myOrg"} 120`)).
Expand All @@ -73,6 +74,7 @@ func TestGithubExporter(t *testing.T) {
Assert(bodyContains(`github_repo_release_downloads{created_at="2019-05-02T15:22:16Z",name="myRepo_2.0.0_windows_amd64.tar.gz",release="2.0.0",repo="myRepo",tag="2.0.0",user="myOrg"} 55`)).
Assert(bodyContains(`github_repo_forks{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myUser"} 10`)).
Assert(bodyContains(`github_repo_pull_request_count{repo="myRepo",user="myUser"} 3`)).
Assert(bodyContains(`github_repo_releases{repo="myRepo",user="myUser"} 2`)).
Assert(bodyContains(`github_repo_open_issues{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myUser"} 2`)).
Assert(bodyContains(`github_repo_size_kb{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myUser"} 946`)).
Assert(bodyContains(`github_repo_stars{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myUser"} 120`)).
Expand All @@ -85,6 +87,29 @@ func TestGithubExporter(t *testing.T) {
End()
}

func TestGithubExporterReleasesDisabled(t *testing.T) {
t.Setenv("FETCH_REPO_RELEASES_ENABLED", "false")
test, collector := apiTest(withConfig())
defer prometheus.Unregister(&collector)

test.Mocks(
githubRepos(),
githubPulls(),
githubUserRepos(),
githubUserPulls(),
githubOrgRepos(),
githubPulls(),
githubRateLimit(),
).
Get("/metrics").
Expect(t).
Assert(bodyContains(`github_repo_stars{archived="false",fork="false",language="Go",license="mit",private="false",repo="myRepo",user="myOrg"} 120`)).
Assert(bodyNotContains(`github_repo_releases`)).
Assert(bodyNotContains(`github_repo_release_downloads`)).
Status(http.StatusOK).
End()
}

func TestGithubExporterHttpErrorHandling(t *testing.T) {
test, collector := apiTest(withConfig())
defer prometheus.Unregister(&collector)
Expand Down Expand Up @@ -239,3 +264,17 @@ func bodyContains(substr string) func(*http.Response, *http.Request) error {
return nil
}
}

func bodyNotContains(substr string) func(*http.Response, *http.Request) error {
return func(res *http.Response, req *http.Request) error {
bytes, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
response := string(bytes)
if strings.Contains(response, substr) {
return fmt.Errorf("response unexpectedly contained substring '%s'", substr)
}
return nil
}
}