This repository has been archived by the owner on Oct 18, 2024. It is now read-only.
forked from erikkn/github-actions-exporter
-
Notifications
You must be signed in to change notification settings - Fork 2
/
collector.go
122 lines (100 loc) · 2.95 KB
/
collector.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/google/go-github/v33/github"
"github.com/prometheus/client_golang/prometheus"
)
type githubRunners struct {
*github.Runners
}
var orgRunnerStatus = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "github_organization_runner_status",
Help: "Status of the self-hosted Github runners in the entire organization. 0 -offline, 1 -idle, 2 -busy",
},
[]string{"name", "id", "size", "env", "self_hosted"},
)
func collectMetrics(t time.Duration) {
for {
orgRunnerStatus.Reset()
orgRunners, err := listOfOrgRunners()
if err != nil {
log.Fatalf("error retrieving the list of organization errors: %s", err)
}
err = orgRunners.setRunnerStatusMetric()
if err != nil {
log.Fatalf("error setting the runner status metrics: %v", err)
}
log.Printf("Fetched %d runners", orgRunners.TotalCount)
time.Sleep(t)
}
}
func init() {
prometheus.MustRegister(orgRunnerStatus)
}
// listOfOrgRunners returns the runners in an organizations
func listOfOrgRunners() (*githubRunners, error) {
ctx := context.Background()
opts := &github.ListOptions{
PerPage: 99,
}
var r []*github.Runner
for {
runners, resp, err := ghClient.Client.Actions.ListOrganizationRunners(ctx, ghClient.Organization, opts)
if err != nil {
return nil, fmt.Errorf("error retrieving runners: %s", err)
}
r = append(r, runners.Runners...)
if resp.NextPage == 0 {
break
}
opts.Page = resp.NextPage
}
return &githubRunners{
&github.Runners{
Runners: r,
TotalCount: len(r),
},
}, nil
}
// setRunnerStatusMetric sets the status of the runners; 0=offline, 1=idle/online, 2=active/busy: https://docs.github.com/en/actions/hosting-your-own-runners/monitoring-and-troubleshooting-self-hosted-runners
//
func (r *githubRunners) setRunnerStatusMetric() error {
for _, v := range r.Runners.Runners {
labels := []string{
*v.Name,
fmt.Sprint(*v.ID),
searchForLabel(v.Labels, []string{"small", "medium", "large", "xlarge", "xxlarge"}, "n/a"),
searchForLabel(v.Labels, []string{"production", "staging", "beta"}, "n/a"),
searchForLabel(v.Labels, []string{"self-hosted"}, "n/a"),
}
if *v.Status == "online" || *v.Status == "idle" {
if *v.Busy {
// Runner is online & busy (executing a job).
orgRunnerStatus.WithLabelValues(labels...).Set(2)
} else {
// Runner is online & idle (waiting for job).
orgRunnerStatus.WithLabelValues(labels...).Set(1)
}
} else if *v.Status == "offline" {
// Runner is offline.
orgRunnerStatus.WithLabelValues(labels...).Set(0)
} else {
return fmt.Errorf("unknown status detected: %s", *v.Status)
}
}
return nil
}
// searchForLabel iterate through list of available labels and return if one of *needles found
func searchForLabel(l []*github.RunnerLabels, needles []string, unknown string) string {
for _, label := range l {
for _, needle := range needles {
if needle == *label.Name {
return *label.Name
}
}
}
return unknown
}