Skip to content

Commit 363c133

Browse files
Fix nil metricsClient panic in kong binding
When no metrics backend is configured, kong's reflection-based binding panics on nil interface values. Replace nil returns with a noopMetrics implementation. 🤖 Generated with [Firebender](https://firebender.com) Co-Authored-By: Firebender <[email protected]>
1 parent 27b601d commit 363c133

3 files changed

Lines changed: 22 additions & 23 deletions

File tree

cmd/gradle-cache/main.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -713,9 +713,7 @@ func main() {
713713
setupLogger(cli.LogLevel)
714714

715715
metrics := cli.newMetricsClient()
716-
if metrics != nil {
717-
defer metrics.close()
718-
}
716+
defer metrics.close()
719717

720718
kctx.FatalIfErrorf(kctx.Run(ctx, metrics))
721719
}

cmd/gradle-cache/metrics.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ type metricsClient interface {
2222
close()
2323
}
2424

25+
// noopMetrics is a no-op metricsClient used when no backend is configured.
26+
// It exists because kong cannot bind a nil interface value.
27+
type noopMetrics struct{}
28+
29+
func (noopMetrics) timing(string, int64, ...string) {}
30+
func (noopMetrics) gauge(string, int64, ...string) {}
31+
func (noopMetrics) close() {}
32+
2533
// metricsFlags are CLI flags for configuring metrics emission.
2634
type metricsFlags struct {
2735
StatsdAddr string `help:"DogStatsD address (host:port) for emitting metrics. Auto-detected from DD_AGENT_HOST if not set."`
@@ -45,14 +53,14 @@ func detectStatsdAddr() string {
4553

4654
// newMetricsClient returns a metricsClient based on the configured flags.
4755
// If no explicit backend is configured, auto-detects a local DD agent.
48-
// Returns nil if no metrics backend is available.
56+
// Returns a no-op client if no metrics backend is available.
4957
func (f *metricsFlags) newMetricsClient() metricsClient {
5058
if f.StatsdAddr != "" {
5159
if c := newStatsdClient(f.StatsdAddr, f.MetricsTags); c != nil {
5260
return c
5361
}
5462
slog.Warn("failed to connect to DogStatsD, metrics disabled", "addr", f.StatsdAddr)
55-
return nil
63+
return noopMetrics{}
5664
}
5765
if f.DatadogAPIKey != "" {
5866
return newDatadogAPIClient(f.DatadogAPIKey, f.MetricsTags)
@@ -64,7 +72,7 @@ func (f *metricsFlags) newMetricsClient() metricsClient {
6472
return c
6573
}
6674
}
67-
return nil
75+
return noopMetrics{}
6876
}
6977

7078
// ── DogStatsD (UDP) ─────────────────────────────────────────────────────────
@@ -169,16 +177,10 @@ func (d *datadogAPIClient) submit(name string, value float64, metricType string,
169177

170178
func (d *datadogAPIClient) close() {}
171179

172-
// emitTiming sends a timing metric if m is non-nil.
173180
func emitTiming(m metricsClient, name string, ms int64, tags ...string) {
174-
if m != nil {
175-
m.timing(name, ms, tags...)
176-
}
181+
m.timing(name, ms, tags...)
177182
}
178183

179-
// emitGauge sends a gauge metric if m is non-nil.
180184
func emitGauge(m metricsClient, name string, value int64, tags ...string) {
181-
if m != nil {
182-
m.gauge(name, value, tags...)
183-
}
185+
m.gauge(name, value, tags...)
184186
}

cmd/gradle-cache/metrics_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,19 @@ func TestStatsdClientGauge(t *testing.T) {
6767
}
6868
}
6969

70-
func TestEmitHelperNilSafe(t *testing.T) {
71-
// Should not panic when metrics is nil.
72-
emitTiming(nil, "test.metric", 100)
73-
emitGauge(nil, "test.metric", 200)
70+
func TestNoopMetrics(t *testing.T) {
71+
// noopMetrics should not panic.
72+
var m metricsClient = noopMetrics{}
73+
emitTiming(m, "test.metric", 100)
74+
emitGauge(m, "test.metric", 200)
75+
m.close()
7476
}
7577

7678
func TestMetricsFlagsNoneConfigured(t *testing.T) {
7779
// Unset DD env vars so auto-detection doesn't interfere.
7880
t.Setenv("DD_AGENT_HOST", "")
7981
f := &metricsFlags{}
8082
m := f.newMetricsClient()
81-
// May be non-nil if a local DD agent happens to be running — that's fine.
82-
// Just verify it doesn't panic.
83-
if m != nil {
84-
m.close()
85-
}
83+
// Should always return a non-nil client (noopMetrics when no backend configured).
84+
m.close()
8685
}

0 commit comments

Comments
 (0)