Include tests
This commit is contained in:
		
							parent
							
								
									07f20cc499
								
							
						
					
					
						commit
						3fb8d12d10
					
				|  | @ -2,6 +2,7 @@ package metrics | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"errors" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  | @ -42,7 +43,18 @@ const ( | ||||||
| 	MetricJobExecutionDurationSeconds = "gha_job_execution_duration_seconds" | 	MetricJobExecutionDurationSeconds = "gha_job_execution_duration_seconds" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var metricsHelp = map[string]string{ | type metricsHelpRegistry struct { | ||||||
|  | 	counters   map[string]string | ||||||
|  | 	gauges     map[string]string | ||||||
|  | 	histograms map[string]string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var metricsHelp = metricsHelpRegistry{ | ||||||
|  | 	counters: map[string]string{ | ||||||
|  | 		MetricStartedJobsTotal:   "Total number of jobs started.", | ||||||
|  | 		MetricCompletedJobsTotal: "Total number of jobs completed.", | ||||||
|  | 	}, | ||||||
|  | 	gauges: map[string]string{ | ||||||
| 		MetricAssignedJobs:      "Number of jobs assigned to this scale set.", | 		MetricAssignedJobs:      "Number of jobs assigned to this scale set.", | ||||||
| 		MetricRunningJobs:       "Number of jobs running (or about to be run).", | 		MetricRunningJobs:       "Number of jobs running (or about to be run).", | ||||||
| 		MetricRegisteredRunners: "Number of runners registered by the scale set.", | 		MetricRegisteredRunners: "Number of runners registered by the scale set.", | ||||||
|  | @ -51,10 +63,11 @@ var metricsHelp = map[string]string{ | ||||||
| 		MetricMaxRunners:        "Maximum number of runners.", | 		MetricMaxRunners:        "Maximum number of runners.", | ||||||
| 		MetricDesiredRunners:    "Number of runners desired by the scale set.", | 		MetricDesiredRunners:    "Number of runners desired by the scale set.", | ||||||
| 		MetricIdleRunners:       "Number of registered runners not running a job.", | 		MetricIdleRunners:       "Number of registered runners not running a job.", | ||||||
| 	MetricStartedJobsTotal:            "Total number of jobs started.", | 	}, | ||||||
| 	MetricCompletedJobsTotal:          "Total number of jobs completed.", | 	histograms: map[string]string{ | ||||||
| 		MetricJobStartupDurationSeconds:   "Time spent waiting for workflow job to get started on the runner owned by the scale set (in seconds).", | 		MetricJobStartupDurationSeconds:   "Time spent waiting for workflow job to get started on the runner owned by the scale set (in seconds).", | ||||||
| 		MetricJobExecutionDurationSeconds: "Time spent executing workflow jobs by the scale set (in seconds).", | 		MetricJobExecutionDurationSeconds: "Time spent executing workflow jobs by the scale set (in seconds).", | ||||||
|  | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (e *exporter) jobLabels(jobBase *actions.JobMessageBase) prometheus.Labels { | func (e *exporter) jobLabels(jobBase *actions.JobMessageBase) prometheus.Labels { | ||||||
|  | @ -142,7 +155,7 @@ type ExporterConfig struct { | ||||||
| func NewExporter(config ExporterConfig) ServerExporter { | func NewExporter(config ExporterConfig) ServerExporter { | ||||||
| 	reg := prometheus.NewRegistry() | 	reg := prometheus.NewRegistry() | ||||||
| 
 | 
 | ||||||
| 	metrics := installMetrics(config.Metrics, reg) | 	metrics := installMetrics(config.Metrics, reg, config.Logger) | ||||||
| 
 | 
 | ||||||
| 	mux := http.NewServeMux() | 	mux := http.NewServeMux() | ||||||
| 	mux.Handle( | 	mux.Handle( | ||||||
|  | @ -167,18 +180,26 @@ func NewExporter(config ExporterConfig) ServerExporter { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func installMetrics(config v1alpha1.MetricsConfig, reg *prometheus.Registry) *metrics { | var errUnknownMetricName = errors.New("unknown metric name") | ||||||
|  | 
 | ||||||
|  | func installMetrics(config v1alpha1.MetricsConfig, reg *prometheus.Registry, logger logr.Logger) *metrics { | ||||||
| 	metrics := &metrics{ | 	metrics := &metrics{ | ||||||
| 		counters:   make(map[string]*counterMetric, len(config.Gauges)), | 		counters:   make(map[string]*counterMetric, len(config.Gauges)), | ||||||
| 		gauges:     make(map[string]*gaugeMetric, len(config.Counters)), | 		gauges:     make(map[string]*gaugeMetric, len(config.Counters)), | ||||||
| 		histograms: make(map[string]*histogramMetric, len(config.Histograms)), | 		histograms: make(map[string]*histogramMetric, len(config.Histograms)), | ||||||
| 	} | 	} | ||||||
| 	for name, cfg := range config.Gauges { | 	for name, cfg := range config.Gauges { | ||||||
|  | 		help, ok := metricsHelp.gauges[name] | ||||||
|  | 		if !ok { | ||||||
|  | 			logger.Error(errUnknownMetricName, "name", name, "kind", "gauge") | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		g := prometheus.V2.NewGaugeVec(prometheus.GaugeVecOpts{ | 		g := prometheus.V2.NewGaugeVec(prometheus.GaugeVecOpts{ | ||||||
| 			GaugeOpts: prometheus.GaugeOpts{ | 			GaugeOpts: prometheus.GaugeOpts{ | ||||||
| 				Subsystem: githubScaleSetSubsystem, | 				Subsystem: githubScaleSetSubsystem, | ||||||
| 				Name:      strings.TrimPrefix(name, githubScaleSetSubsystem), | 				Name:      strings.TrimPrefix(name, githubScaleSetSubsystem), | ||||||
| 				Help:      metricsHelp[name], | 				Help:      help, | ||||||
| 			}, | 			}, | ||||||
| 			VariableLabels: prometheus.UnconstrainedLabels(cfg.Labels), | 			VariableLabels: prometheus.UnconstrainedLabels(cfg.Labels), | ||||||
| 		}) | 		}) | ||||||
|  | @ -190,11 +211,16 @@ func installMetrics(config v1alpha1.MetricsConfig, reg *prometheus.Registry) *me | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for name, cfg := range config.Counters { | 	for name, cfg := range config.Counters { | ||||||
|  | 		help, ok := metricsHelp.counters[name] | ||||||
|  | 		if !ok { | ||||||
|  | 			logger.Error(errUnknownMetricName, "name", name, "kind", "counter") | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
| 		c := prometheus.V2.NewCounterVec(prometheus.CounterVecOpts{ | 		c := prometheus.V2.NewCounterVec(prometheus.CounterVecOpts{ | ||||||
| 			CounterOpts: prometheus.CounterOpts{ | 			CounterOpts: prometheus.CounterOpts{ | ||||||
| 				Subsystem: githubScaleSetSubsystem, | 				Subsystem: githubScaleSetSubsystem, | ||||||
| 				Name:      strings.TrimPrefix(name, githubScaleSetSubsystem), | 				Name:      strings.TrimPrefix(name, githubScaleSetSubsystem), | ||||||
| 				Help:      metricsHelp[name], | 				Help:      help, | ||||||
| 			}, | 			}, | ||||||
| 			VariableLabels: prometheus.UnconstrainedLabels(cfg.Labels), | 			VariableLabels: prometheus.UnconstrainedLabels(cfg.Labels), | ||||||
| 		}) | 		}) | ||||||
|  | @ -206,6 +232,12 @@ func installMetrics(config v1alpha1.MetricsConfig, reg *prometheus.Registry) *me | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for name, cfg := range config.Histograms { | 	for name, cfg := range config.Histograms { | ||||||
|  | 		help, ok := metricsHelp.histograms[name] | ||||||
|  | 		if !ok { | ||||||
|  | 			logger.Error(errUnknownMetricName, "name", name, "kind", "histogram") | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		buckets := defaultRuntimeBuckets | 		buckets := defaultRuntimeBuckets | ||||||
| 		if len(cfg.Buckets) > 0 { | 		if len(cfg.Buckets) > 0 { | ||||||
| 			buckets = cfg.Buckets | 			buckets = cfg.Buckets | ||||||
|  | @ -214,11 +246,12 @@ func installMetrics(config v1alpha1.MetricsConfig, reg *prometheus.Registry) *me | ||||||
| 			HistogramOpts: prometheus.HistogramOpts{ | 			HistogramOpts: prometheus.HistogramOpts{ | ||||||
| 				Subsystem: githubScaleSetSubsystem, | 				Subsystem: githubScaleSetSubsystem, | ||||||
| 				Name:      strings.TrimPrefix(name, githubScaleSetSubsystem), | 				Name:      strings.TrimPrefix(name, githubScaleSetSubsystem), | ||||||
| 				Help:      metricsHelp[name], | 				Help:      help, | ||||||
| 				Buckets:   buckets, | 				Buckets:   buckets, | ||||||
| 			}, | 			}, | ||||||
| 			VariableLabels: prometheus.UnconstrainedLabels(cfg.Labels), | 			VariableLabels: prometheus.UnconstrainedLabels(cfg.Labels), | ||||||
| 		}) | 		}) | ||||||
|  | 		cfg.Buckets = buckets | ||||||
| 		reg.MustRegister(h) | 		reg.MustRegister(h) | ||||||
| 		metrics.histograms[name] = &histogramMetric{ | 		metrics.histograms[name] = &histogramMetric{ | ||||||
| 			histogram: h, | 			histogram: h, | ||||||
|  |  | ||||||
|  | @ -0,0 +1,88 @@ | ||||||
|  | package metrics | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" | ||||||
|  | 	"github.com/go-logr/logr" | ||||||
|  | 	"github.com/prometheus/client_golang/prometheus" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestInstallMetrics(t *testing.T) { | ||||||
|  | 	metricsConfig := v1alpha1.MetricsConfig{ | ||||||
|  | 		Counters: map[string]*v1alpha1.CounterMetric{ | ||||||
|  | 			// unknown metric shouldn't be registered
 | ||||||
|  | 			"gha_unknown": { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// gauge metric shouldn't be registered from this section
 | ||||||
|  | 			MetricAssignedJobs: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// histogram metric shouldn't be registered from this section
 | ||||||
|  | 			MetricJobStartupDurationSeconds: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// counter metric should be registered
 | ||||||
|  | 			MetricStartedJobsTotal: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		Gauges: map[string]*v1alpha1.GaugeMetric{ | ||||||
|  | 			// unknown metric shouldn't be registered
 | ||||||
|  | 			"gha_unknown": { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// counter metric shouldn't be registered from this section
 | ||||||
|  | 			MetricStartedJobsTotal: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// histogram metric shouldn't be registered from this section
 | ||||||
|  | 			MetricJobStartupDurationSeconds: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// gauge metric should be registered
 | ||||||
|  | 			MetricAssignedJobs: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		Histograms: map[string]*v1alpha1.HistogramMetric{ | ||||||
|  | 			// unknown metric shouldn't be registered
 | ||||||
|  | 			"gha_unknown": { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// counter metric shouldn't be registered from this section
 | ||||||
|  | 			MetricStartedJobsTotal: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// gauge metric shouldn't be registered from this section
 | ||||||
|  | 			MetricAssignedJobs: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 			// histogram metric should be registered
 | ||||||
|  | 			MetricJobExecutionDurationSeconds: { | ||||||
|  | 				Labels:  []string{labelKeyRepository}, | ||||||
|  | 				Buckets: []float64{0.1, 1}, | ||||||
|  | 			}, | ||||||
|  | 			// histogram metric should be registered with default runtime buckets
 | ||||||
|  | 			MetricJobStartupDurationSeconds: { | ||||||
|  | 				Labels: []string{labelKeyRepository}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	reg := prometheus.NewRegistry() | ||||||
|  | 
 | ||||||
|  | 	got := installMetrics(metricsConfig, reg, logr.Discard()) | ||||||
|  | 	assert.Len(t, got.counters, 1) | ||||||
|  | 	assert.Len(t, got.gauges, 1) | ||||||
|  | 	assert.Len(t, got.histograms, 2) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(t, got.counters[MetricStartedJobsTotal].config, metricsConfig.Counters[MetricStartedJobsTotal]) | ||||||
|  | 	assert.Equal(t, got.gauges[MetricAssignedJobs].config, metricsConfig.Gauges[MetricAssignedJobs]) | ||||||
|  | 	assert.Equal(t, got.histograms[MetricJobExecutionDurationSeconds].config, metricsConfig.Histograms[MetricJobExecutionDurationSeconds]) | ||||||
|  | 
 | ||||||
|  | 	duration := got.histograms[MetricJobStartupDurationSeconds] | ||||||
|  | 	assert.Equal(t, duration.config.Labels, metricsConfig.Histograms[MetricJobStartupDurationSeconds].Labels) | ||||||
|  | 	assert.Equal(t, duration.config.Buckets, defaultRuntimeBuckets) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue