[inputs.github] Add query of pull-request statistics (#8500)
This commit is contained in:
parent
9166a16577
commit
34151c47a6
|
|
@ -23,6 +23,14 @@ alternative method for collecting repository information.
|
||||||
|
|
||||||
## Timeout for HTTP requests.
|
## Timeout for HTTP requests.
|
||||||
# http_timeout = "5s"
|
# http_timeout = "5s"
|
||||||
|
|
||||||
|
## List of additional fields to query.
|
||||||
|
## NOTE: Getting those fields might involve issuing additional API-calls, so please
|
||||||
|
## make sure you do not exceed the rate-limit of GitHub.
|
||||||
|
##
|
||||||
|
## Available fields are:
|
||||||
|
## - pull-requests -- number of open and closed pull requests (2 API-calls per repository)
|
||||||
|
# additional_fields = []
|
||||||
```
|
```
|
||||||
|
|
||||||
### Metrics
|
### Metrics
|
||||||
|
|
@ -52,11 +60,21 @@ When the [internal][] input is enabled:
|
||||||
- remaining - How many requests you have remaining (per hour)
|
- remaining - How many requests you have remaining (per hour)
|
||||||
- blocks - How many requests have been blocked due to rate limit
|
- blocks - How many requests have been blocked due to rate limit
|
||||||
|
|
||||||
|
When specifying `additional_fields` the plugin will collect the specified properties.
|
||||||
|
**NOTE:** Querying this additional fields might require to perform additional API-calls.
|
||||||
|
Please make sure you don't exceed the query rate-limit by specifying too many additional fields.
|
||||||
|
In the following we list the available options with the required API-calls and the resulting fields
|
||||||
|
|
||||||
|
- "pull-requests" (2 API-calls per repository)
|
||||||
|
- fields:
|
||||||
|
- open_pull_requests (int)
|
||||||
|
- closed_pull_requests (int)
|
||||||
|
|
||||||
### Example Output
|
### Example Output
|
||||||
|
|
||||||
```
|
```
|
||||||
github_repository,language=Go,license=MIT\ License,name=telegraf,owner=influxdata forks=2679i,networks=2679i,open_issues=794i,size=23263i,stars=7091i,subscribers=316i,watchers=7091i 1563901372000000000
|
github_repository,language=Go,license=MIT\ License,name=telegraf,owner=influxdata forks=2679i,networks=2679i,open_issues=794i,size=23263i,stars=7091i,subscribers=316i,watchers=7091i 1563901372000000000
|
||||||
internal_github,access_token=Unauthenticated rate_limit_remaining=59i,rate_limit_limit=60i,rate_limit_blocks=0i 1552653551000000000
|
internal_github,access_token=Unauthenticated closed_pull_requests=3522i,rate_limit_remaining=59i,rate_limit_limit=60i,rate_limit_blocks=0i,open_pull_requests=260i 1552653551000000000
|
||||||
```
|
```
|
||||||
|
|
||||||
[GitHub]: https://www.github.com
|
[GitHub]: https://www.github.com
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
type GitHub struct {
|
type GitHub struct {
|
||||||
Repositories []string `toml:"repositories"`
|
Repositories []string `toml:"repositories"`
|
||||||
AccessToken string `toml:"access_token"`
|
AccessToken string `toml:"access_token"`
|
||||||
|
AdditionalFields []string `toml:"additional_fields"`
|
||||||
EnterpriseBaseURL string `toml:"enterprise_base_url"`
|
EnterpriseBaseURL string `toml:"enterprise_base_url"`
|
||||||
HTTPTimeout internal.Duration `toml:"http_timeout"`
|
HTTPTimeout internal.Duration `toml:"http_timeout"`
|
||||||
githubClient *github.Client
|
githubClient *github.Client
|
||||||
|
|
@ -46,6 +47,14 @@ const sampleConfig = `
|
||||||
|
|
||||||
## Timeout for HTTP requests.
|
## Timeout for HTTP requests.
|
||||||
# http_timeout = "5s"
|
# http_timeout = "5s"
|
||||||
|
|
||||||
|
## List of additional fields to query.
|
||||||
|
## NOTE: Getting those fields might involve issuing additional API-calls, so please
|
||||||
|
## make sure you do not exceed the rate-limit of GitHub.
|
||||||
|
##
|
||||||
|
## Available fields are:
|
||||||
|
## - pull-requests -- number of open and closed pull requests (2 API-calls per repository)
|
||||||
|
# additional_fields = []
|
||||||
`
|
`
|
||||||
|
|
||||||
// SampleConfig returns sample configuration for this plugin.
|
// SampleConfig returns sample configuration for this plugin.
|
||||||
|
|
@ -97,7 +106,6 @@ func (g *GitHub) Gather(acc telegraf.Accumulator) error {
|
||||||
|
|
||||||
if g.githubClient == nil {
|
if g.githubClient == nil {
|
||||||
githubClient, err := g.createGitHubClient(ctx)
|
githubClient, err := g.createGitHubClient(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -127,23 +135,35 @@ func (g *GitHub) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
repositoryInfo, response, err := g.githubClient.Repositories.Get(ctx, owner, repository)
|
repositoryInfo, response, err := g.githubClient.Repositories.Get(ctx, owner, repository)
|
||||||
|
g.handleRateLimit(response, err)
|
||||||
if _, ok := err.(*github.RateLimitError); ok {
|
|
||||||
g.RateLimitErrors.Incr(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
acc.AddError(err)
|
acc.AddError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.RateLimit.Set(int64(response.Rate.Limit))
|
|
||||||
g.RateRemaining.Set(int64(response.Rate.Remaining))
|
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
tags := getTags(repositoryInfo)
|
tags := getTags(repositoryInfo)
|
||||||
fields := getFields(repositoryInfo)
|
fields := getFields(repositoryInfo)
|
||||||
|
|
||||||
|
for _, field := range g.AdditionalFields {
|
||||||
|
addFields := make(map[string]interface{})
|
||||||
|
switch field {
|
||||||
|
case "pull-requests":
|
||||||
|
// Pull request properties
|
||||||
|
addFields, err = g.getPullRequestFields(ctx, owner, repository)
|
||||||
|
if err != nil {
|
||||||
|
acc.AddError(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
acc.AddError(fmt.Errorf("unknown additional field %q", field))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for k, v := range addFields {
|
||||||
|
fields[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
acc.AddFields("github_repository", fields, tags, now)
|
acc.AddFields("github_repository", fields, tags, now)
|
||||||
}(repository, acc)
|
}(repository, acc)
|
||||||
}
|
}
|
||||||
|
|
@ -152,6 +172,15 @@ func (g *GitHub) Gather(acc telegraf.Accumulator) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GitHub) handleRateLimit(response *github.Response, err error) {
|
||||||
|
if err == nil {
|
||||||
|
g.RateLimit.Set(int64(response.Rate.Limit))
|
||||||
|
g.RateRemaining.Set(int64(response.Rate.Remaining))
|
||||||
|
} else if _, ok := err.(*github.RateLimitError); ok {
|
||||||
|
g.RateLimitErrors.Incr(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func splitRepositoryName(repositoryName string) (string, string, error) {
|
func splitRepositoryName(repositoryName string) (string, string, error) {
|
||||||
splits := strings.SplitN(repositoryName, "/", 2)
|
splits := strings.SplitN(repositoryName, "/", 2)
|
||||||
|
|
||||||
|
|
@ -191,6 +220,32 @@ func getFields(repositoryInfo *github.Repository) map[string]interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GitHub) getPullRequestFields(ctx context.Context, owner, repo string) (map[string]interface{}, error) {
|
||||||
|
options := github.SearchOptions{
|
||||||
|
TextMatch: false,
|
||||||
|
ListOptions: github.ListOptions{
|
||||||
|
PerPage: 100,
|
||||||
|
Page: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
classes := []string{"open", "closed"}
|
||||||
|
fields := make(map[string]interface{})
|
||||||
|
for _, class := range classes {
|
||||||
|
q := fmt.Sprintf("repo:%s/%s is:pr is:%s", owner, repo, class)
|
||||||
|
searchResult, response, err := g.githubClient.Search.Issues(ctx, q, &options)
|
||||||
|
g.handleRateLimit(response, err)
|
||||||
|
if err != nil {
|
||||||
|
return fields, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := fmt.Sprintf("%s_pull_requests", class)
|
||||||
|
fields[f] = searchResult.GetTotal()
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
inputs.Add("github", func() telegraf.Input {
|
inputs.Add("github", func() telegraf.Input {
|
||||||
return &GitHub{
|
return &GitHub{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue