diff --git a/charts/gha-runner-scale-set/values.yaml b/charts/gha-runner-scale-set/values.yaml index c602dd2280..b66c91ce11 100644 --- a/charts/gha-runner-scale-set/values.yaml +++ b/charts/gha-runner-scale-set/values.yaml @@ -154,7 +154,7 @@ githubConfigSecret: # counters: # gha_started_jobs_total: # labels: -# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref"] +# ["repository", "organization", "enterprise", "job_name", "event_name", "job_workflow_ref", "runner_name"] # gha_completed_jobs_total: # labels: # [ @@ -165,6 +165,7 @@ githubConfigSecret: # "event_name", # "job_result", # "job_workflow_ref", +# "runner_name", # ] # gauges: # gha_assigned_jobs: @@ -186,7 +187,7 @@ githubConfigSecret: # histograms: # gha_job_startup_duration_seconds: # labels: -# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref"] +# ["repository", "organization", "enterprise", "job_name", "event_name","job_workflow_ref", "runner_name"] # buckets: # [ # 0.01, @@ -244,7 +245,8 @@ githubConfigSecret: # "job_name", # "event_name", # "job_result", -# "job_workflow_ref" +# "job_workflow_ref", +# "runner_name" # ] # buckets: # [ diff --git a/cmd/ghalistener/metrics/metrics.go b/cmd/ghalistener/metrics/metrics.go index 2aed6fb81d..7f0c3714b8 100644 --- a/cmd/ghalistener/metrics/metrics.go +++ b/cmd/ghalistener/metrics/metrics.go @@ -24,6 +24,7 @@ const ( labelKeyJobWorkflowRef = "job_workflow_ref" labelKeyEventName = "event_name" labelKeyJobResult = "job_result" + labelKeyRunnerName = "runner_name" ) const ( @@ -88,11 +89,14 @@ func (e *exporter) jobLabels(jobBase *actions.JobMessageBase) prometheus.Labels func (e *exporter) completedJobLabels(msg *actions.JobCompleted) prometheus.Labels { l := e.jobLabels(&msg.JobMessageBase) l[labelKeyJobResult] = msg.Result + l[labelKeyRunnerName] = msg.RunnerName return l } func (e *exporter) startedJobLabels(msg *actions.JobStarted) prometheus.Labels { - return e.jobLabels(&msg.JobMessageBase) + l := e.jobLabels(&msg.JobMessageBase) + l[labelKeyRunnerName] = msg.RunnerName + return l } //go:generate mockery --name Publisher --output ./mocks --outpkg mocks --case underscore @@ -411,6 +415,14 @@ func installMetrics(config v1alpha1.MetricsConfig, reg *prometheus.Registry, log return metrics } +func configuredLabelsOnly(allLabels prometheus.Labels, configuredLabels []string) prometheus.Labels { + labels := make(prometheus.Labels, len(configuredLabels)) + for _, label := range configuredLabels { + labels[label] = allLabels[label] + } + return labels +} + func (e *exporter) ListenAndServe(ctx context.Context) error { e.logger.Info("starting metrics server", "addr", e.srv.Addr) go func() { @@ -428,10 +440,7 @@ func (e *exporter) setGauge(name string, allLabels prometheus.Labels, val float6 if !ok { return } - labels := make(prometheus.Labels, len(m.config.Labels)) - for _, label := range m.config.Labels { - labels[label] = allLabels[label] - } + labels := configuredLabelsOnly(allLabels, m.config.Labels) m.gauge.With(labels).Set(val) } @@ -440,10 +449,7 @@ func (e *exporter) incCounter(name string, allLabels prometheus.Labels) { if !ok { return } - labels := make(prometheus.Labels, len(m.config.Labels)) - for _, label := range m.config.Labels { - labels[label] = allLabels[label] - } + labels := configuredLabelsOnly(allLabels, m.config.Labels) m.counter.With(labels).Inc() } @@ -452,10 +458,7 @@ func (e *exporter) observeHistogram(name string, allLabels prometheus.Labels, va if !ok { return } - labels := make(prometheus.Labels, len(m.config.Labels)) - for _, label := range m.config.Labels { - labels[label] = allLabels[label] - } + labels := configuredLabelsOnly(allLabels, m.config.Labels) m.histogram.With(labels).Observe(val) } diff --git a/cmd/ghalistener/metrics/metrics_test.go b/cmd/ghalistener/metrics/metrics_test.go index 850560fbc1..bf91074e0c 100644 --- a/cmd/ghalistener/metrics/metrics_test.go +++ b/cmd/ghalistener/metrics/metrics_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" + "github.com/actions/actions-runner-controller/github/actions" "github.com/go-logr/logr" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" @@ -263,3 +264,113 @@ func TestExporterConfigDefaults(t *testing.T) { assert.Equal(t, want, config) } + +func TestConfiguredLabelsOnly(t *testing.T) { + allLabels := prometheus.Labels{ + labelKeyRepository: "test-repo", + labelKeyOrganization: "test-org", + labelKeyJobName: "test-job", + } + + configuredLabels := []string{labelKeyRepository, labelKeyJobName} + + got := configuredLabelsOnly(allLabels, configuredLabels) + + want := prometheus.Labels{ + labelKeyRepository: "test-repo", + labelKeyJobName: "test-job", + } + + assert.Equal(t, want, got) + assert.NotContains(t, got, labelKeyOrganization) +} + +func TestCompletedJobAllLabels(t *testing.T) { + config := ExporterConfig{ + ScaleSetName: "test-scale-set", + ScaleSetNamespace: "test-namespace", + Enterprise: "", + Organization: "org", + Repository: "repo", + ServerAddr: "", + ServerEndpoint: "", + Logger: logr.Discard(), + Metrics: nil, // when metrics is nil, all default metrics should be registered + } + + exporter, ok := NewExporter(config).(*exporter) + require.True(t, ok, "expected exporter to be of type *exporter") + require.NotNil(t, exporter) + + jobMessage := &actions.JobCompleted{ + JobMessageBase: actions.JobMessageBase{ + RepositoryName: "repo", + OwnerName: "org", + EventName: "", + JobDisplayName: "test-job", + JobWorkflowRef: "org/repo/.github/workflows/test.yml", + }, + Result: "success", + RunnerId: 1, + RunnerName: "runner1", + } + + labels := exporter.completedJobLabels(jobMessage) + + want := prometheus.Labels{ + labelKeyEnterprise: "", + labelKeyRepository: "repo", + labelKeyJobName: "test-job", + labelKeyOrganization: "org", + labelKeyEventName: "", + labelKeyJobWorkflowRef: "org/repo/.github/workflows/test.yml", + labelKeyJobResult: "success", + labelKeyRunnerName: "runner1", + } + + assert.Equal(t, want, labels) +} + +func TestStartedJobAllLabels(t *testing.T) { + config := ExporterConfig{ + ScaleSetName: "test-scale-set", + ScaleSetNamespace: "test-namespace", + Enterprise: "", + Organization: "org", + Repository: "repo", + ServerAddr: "", + ServerEndpoint: "", + Logger: logr.Discard(), + Metrics: nil, // when metrics is nil, all default metrics should be registered + } + + exporter, ok := NewExporter(config).(*exporter) + require.True(t, ok, "expected exporter to be of type *exporter") + require.NotNil(t, exporter) + + jobMessage := &actions.JobStarted{ + JobMessageBase: actions.JobMessageBase{ + RepositoryName: "repo", + OwnerName: "org", + EventName: "", + JobDisplayName: "test-job", + JobWorkflowRef: "org/repo/.github/workflows/test.yml", + }, + RunnerId: 1, + RunnerName: "runner1", + } + + labels := exporter.startedJobLabels(jobMessage) + + want := prometheus.Labels{ + labelKeyEnterprise: "", + labelKeyRepository: "repo", + labelKeyJobName: "test-job", + labelKeyOrganization: "org", + labelKeyEventName: "", + labelKeyJobWorkflowRef: "org/repo/.github/workflows/test.yml", + labelKeyRunnerName: "runner1", + } + + assert.Equal(t, want, labels) +}