Avoid nil point when config.Metrics is nil and expose all metrics if none are configured (#4101)
Co-authored-by: Nikola Jokic <jokicnikola07@gmail.com>
This commit is contained in:
parent
9d8c59aeb3
commit
c359d14e69
|
|
@ -69,8 +69,8 @@ func New(config config.Config) (*App, error) {
|
|||
Repository: ghConfig.Repository,
|
||||
ServerAddr: config.MetricsAddr,
|
||||
ServerEndpoint: config.MetricsEndpoint,
|
||||
Metrics: config.Metrics,
|
||||
Logger: app.logger.WithName("metrics exporter"),
|
||||
Metrics: *config.Metrics,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,13 +154,148 @@ type ExporterConfig struct {
|
|||
ServerAddr string
|
||||
ServerEndpoint string
|
||||
Logger logr.Logger
|
||||
Metrics v1alpha1.MetricsConfig
|
||||
Metrics *v1alpha1.MetricsConfig
|
||||
}
|
||||
|
||||
var defaultMetrics = v1alpha1.MetricsConfig{
|
||||
Counters: map[string]*v1alpha1.CounterMetric{
|
||||
MetricStartedJobsTotal: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyJobName,
|
||||
labelKeyEventName,
|
||||
},
|
||||
},
|
||||
MetricCompletedJobsTotal: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyJobName,
|
||||
labelKeyEventName,
|
||||
labelKeyJobResult,
|
||||
},
|
||||
},
|
||||
},
|
||||
Gauges: map[string]*v1alpha1.GaugeMetric{
|
||||
MetricAssignedJobs: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricRunningJobs: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricRegisteredRunners: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricBusyRunners: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricMinRunners: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricMaxRunners: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricDesiredRunners: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
MetricIdleRunners: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyRunnerScaleSetName,
|
||||
labelKeyRunnerScaleSetNamespace,
|
||||
},
|
||||
},
|
||||
},
|
||||
Histograms: map[string]*v1alpha1.HistogramMetric{
|
||||
MetricJobStartupDurationSeconds: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyJobName,
|
||||
labelKeyEventName,
|
||||
},
|
||||
Buckets: defaultRuntimeBuckets,
|
||||
},
|
||||
MetricJobExecutionDurationSeconds: {
|
||||
Labels: []string{
|
||||
labelKeyEnterprise,
|
||||
labelKeyOrganization,
|
||||
labelKeyRepository,
|
||||
labelKeyJobName,
|
||||
labelKeyEventName,
|
||||
labelKeyJobResult,
|
||||
},
|
||||
Buckets: defaultRuntimeBuckets,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func (e *ExporterConfig) defaults() {
|
||||
if e.ServerAddr == "" {
|
||||
e.ServerAddr = ":8080"
|
||||
}
|
||||
if e.ServerEndpoint == "" {
|
||||
e.ServerEndpoint = "/metrics"
|
||||
}
|
||||
if e.Metrics == nil {
|
||||
defaultMetrics := defaultMetrics
|
||||
e.Metrics = &defaultMetrics
|
||||
}
|
||||
}
|
||||
|
||||
func NewExporter(config ExporterConfig) ServerExporter {
|
||||
config.defaults()
|
||||
reg := prometheus.NewRegistry()
|
||||
|
||||
metrics := installMetrics(config.Metrics, reg, config.Logger)
|
||||
metrics := installMetrics(*config.Metrics, reg, config.Logger)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInstallMetrics(t *testing.T) {
|
||||
|
|
@ -86,3 +87,179 @@ func TestInstallMetrics(t *testing.T) {
|
|||
assert.Equal(t, duration.config.Labels, metricsConfig.Histograms[MetricJobStartupDurationSeconds].Labels)
|
||||
assert.Equal(t, duration.config.Buckets, defaultRuntimeBuckets)
|
||||
}
|
||||
|
||||
func TestNewExporter(t *testing.T) {
|
||||
t.Run("with defaults metrics applied", func(t *testing.T) {
|
||||
config := ExporterConfig{
|
||||
ScaleSetName: "test-scale-set",
|
||||
ScaleSetNamespace: "test-namespace",
|
||||
Enterprise: "",
|
||||
Organization: "org",
|
||||
Repository: "repo",
|
||||
ServerAddr: ":6060",
|
||||
ServerEndpoint: "/metrics",
|
||||
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)
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
wantMetrics := installMetrics(defaultMetrics, reg, config.Logger)
|
||||
|
||||
assert.Equal(t, len(wantMetrics.counters), len(exporter.counters))
|
||||
for k, v := range wantMetrics.counters {
|
||||
assert.Contains(t, exporter.counters, k)
|
||||
assert.Equal(t, v.config, exporter.counters[k].config)
|
||||
}
|
||||
|
||||
assert.Equal(t, len(wantMetrics.gauges), len(exporter.gauges))
|
||||
for k, v := range wantMetrics.gauges {
|
||||
assert.Contains(t, exporter.gauges, k)
|
||||
assert.Equal(t, v.config, exporter.gauges[k].config)
|
||||
}
|
||||
|
||||
assert.Equal(t, len(wantMetrics.histograms), len(exporter.histograms))
|
||||
for k, v := range wantMetrics.histograms {
|
||||
assert.Contains(t, exporter.histograms, k)
|
||||
assert.Equal(t, v.config, exporter.histograms[k].config)
|
||||
}
|
||||
|
||||
require.NotNil(t, exporter.srv)
|
||||
assert.Equal(t, config.ServerAddr, exporter.srv.Addr)
|
||||
})
|
||||
|
||||
t.Run("with default server URL", func(t *testing.T) {
|
||||
config := ExporterConfig{
|
||||
ScaleSetName: "test-scale-set",
|
||||
ScaleSetNamespace: "test-namespace",
|
||||
Enterprise: "",
|
||||
Organization: "org",
|
||||
Repository: "repo",
|
||||
ServerAddr: "", // empty ServerAddr should default to ":8080"
|
||||
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)
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
wantMetrics := installMetrics(defaultMetrics, reg, config.Logger)
|
||||
|
||||
assert.Equal(t, len(wantMetrics.counters), len(exporter.counters))
|
||||
for k, v := range wantMetrics.counters {
|
||||
assert.Contains(t, exporter.counters, k)
|
||||
assert.Equal(t, v.config, exporter.counters[k].config)
|
||||
}
|
||||
|
||||
assert.Equal(t, len(wantMetrics.gauges), len(exporter.gauges))
|
||||
for k, v := range wantMetrics.gauges {
|
||||
assert.Contains(t, exporter.gauges, k)
|
||||
assert.Equal(t, v.config, exporter.gauges[k].config)
|
||||
}
|
||||
|
||||
assert.Equal(t, len(wantMetrics.histograms), len(exporter.histograms))
|
||||
for k, v := range wantMetrics.histograms {
|
||||
assert.Contains(t, exporter.histograms, k)
|
||||
assert.Equal(t, v.config, exporter.histograms[k].config)
|
||||
}
|
||||
|
||||
require.NotNil(t, exporter.srv)
|
||||
assert.Equal(t, exporter.srv.Addr, ":8080")
|
||||
})
|
||||
|
||||
t.Run("with metrics configured", func(t *testing.T) {
|
||||
metricsConfig := v1alpha1.MetricsConfig{
|
||||
Counters: map[string]*v1alpha1.CounterMetric{
|
||||
MetricStartedJobsTotal: {
|
||||
Labels: []string{labelKeyRepository},
|
||||
},
|
||||
},
|
||||
Gauges: map[string]*v1alpha1.GaugeMetric{
|
||||
MetricAssignedJobs: {
|
||||
Labels: []string{labelKeyRepository},
|
||||
},
|
||||
},
|
||||
Histograms: map[string]*v1alpha1.HistogramMetric{
|
||||
MetricJobExecutionDurationSeconds: {
|
||||
Labels: []string{labelKeyRepository},
|
||||
Buckets: []float64{0.1, 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
config := ExporterConfig{
|
||||
ScaleSetName: "test-scale-set",
|
||||
ScaleSetNamespace: "test-namespace",
|
||||
Enterprise: "",
|
||||
Organization: "org",
|
||||
Repository: "repo",
|
||||
ServerAddr: ":6060",
|
||||
ServerEndpoint: "/metrics",
|
||||
Logger: logr.Discard(),
|
||||
Metrics: &metricsConfig,
|
||||
}
|
||||
|
||||
exporter, ok := NewExporter(config).(*exporter)
|
||||
require.True(t, ok, "expected exporter to be of type *exporter")
|
||||
require.NotNil(t, exporter)
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
wantMetrics := installMetrics(metricsConfig, reg, config.Logger)
|
||||
|
||||
assert.Equal(t, len(wantMetrics.counters), len(exporter.counters))
|
||||
for k, v := range wantMetrics.counters {
|
||||
assert.Contains(t, exporter.counters, k)
|
||||
assert.Equal(t, v.config, exporter.counters[k].config)
|
||||
}
|
||||
|
||||
assert.Equal(t, len(wantMetrics.gauges), len(exporter.gauges))
|
||||
for k, v := range wantMetrics.gauges {
|
||||
assert.Contains(t, exporter.gauges, k)
|
||||
assert.Equal(t, v.config, exporter.gauges[k].config)
|
||||
}
|
||||
|
||||
assert.Equal(t, len(wantMetrics.histograms), len(exporter.histograms))
|
||||
for k, v := range wantMetrics.histograms {
|
||||
assert.Contains(t, exporter.histograms, k)
|
||||
assert.Equal(t, v.config, exporter.histograms[k].config)
|
||||
}
|
||||
|
||||
require.NotNil(t, exporter.srv)
|
||||
assert.Equal(t, config.ServerAddr, exporter.srv.Addr)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExporterConfigDefaults(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
|
||||
}
|
||||
|
||||
config.defaults()
|
||||
want := ExporterConfig{
|
||||
ScaleSetName: "test-scale-set",
|
||||
ScaleSetNamespace: "test-namespace",
|
||||
Enterprise: "",
|
||||
Organization: "org",
|
||||
Repository: "repo",
|
||||
ServerAddr: ":8080", // default server address
|
||||
ServerEndpoint: "/metrics", // default server endpoint
|
||||
Logger: logr.Discard(),
|
||||
Metrics: &defaultMetrics, // when metrics is nil, all default metrics should be registered
|
||||
}
|
||||
|
||||
assert.Equal(t, want, config)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue