Skip to content

Commit bf87eec

Browse files
Update nginx-prometheus-exporter to 1.0.0 (#1347)
Problem: The new version of the NGINX Prometheus Exporter introduces a couple of breaking changes. One of these changes is that the exporter now requires a logger to be passed to the collectors. This logger interface is incompatible with NGF's logger. Solution: Update to version 1.0.0 of the NGINX Prometheus Exporter and fix errors. Wraps the Prometheus exporter logger in an interface so that we can control its log level alongside our base logger.
1 parent 51e6109 commit bf87eec

File tree

11 files changed

+501
-79
lines changed

11 files changed

+501
-79
lines changed

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ go 1.21.3
66
replace github.com/chzyer/logex v1.1.10 => github.com/chzyer/logex v1.2.0
77

88
require (
9+
github.com/go-kit/log v0.2.1
910
github.com/go-logr/logr v1.4.1
1011
github.com/google/go-cmp v0.6.0
1112
github.com/maxbrunsfeld/counterfeiter/v6 v6.7.0
12-
github.com/nginxinc/nginx-plus-go-client v0.10.0
13-
github.com/nginxinc/nginx-prometheus-exporter v0.11.0
13+
github.com/nginxinc/nginx-plus-go-client v1.2.0
14+
github.com/nginxinc/nginx-prometheus-exporter v1.0.0
1415
github.com/onsi/ginkgo/v2 v2.13.2
1516
github.com/onsi/gomega v1.30.0
1617
github.com/prometheus/client_golang v1.18.0
18+
github.com/prometheus/common v0.45.0
1719
github.com/spf13/cobra v1.8.0
1820
github.com/tsenart/vegeta/v12 v12.11.1
1921
go.uber.org/zap v1.26.0
@@ -36,6 +38,7 @@ require (
3638
github.com/evanphx/json-patch/v5 v5.7.0 // indirect
3739
github.com/fatih/color v1.15.0 // indirect
3840
github.com/fsnotify/fsnotify v1.7.0 // indirect
41+
github.com/go-logfmt/logfmt v0.5.1 // indirect
3942
github.com/go-logr/zapr v1.2.4 // indirect
4043
github.com/go-openapi/jsonpointer v0.20.0 // indirect
4144
github.com/go-openapi/jsonreference v0.20.2 // indirect
@@ -67,7 +70,6 @@ require (
6770
github.com/pkg/errors v0.9.1 // indirect
6871
github.com/pmezard/go-difflib v1.0.0 // indirect
6972
github.com/prometheus/client_model v0.5.0 // indirect
70-
github.com/prometheus/common v0.45.0 // indirect
7173
github.com/prometheus/procfs v0.12.0 // indirect
7274
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect
7375
github.com/spf13/pflag v1.0.5 // indirect

go.sum

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
2727
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
2828
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
2929
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
30+
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
31+
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
32+
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
33+
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
3034
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
3135
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
3236
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
@@ -113,10 +117,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
113117
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
114118
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
115119
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
116-
github.com/nginxinc/nginx-plus-go-client v0.10.0 h1:3zsMMkPvRDo8D7ZSprXtbAEW/SDmezZWzxdyS+6oAlc=
117-
github.com/nginxinc/nginx-plus-go-client v0.10.0/go.mod h1:0v3RsQCvRn/IyrMtW+DK6CNkz+PxEsXDJPjQ3yUMBF0=
118-
github.com/nginxinc/nginx-prometheus-exporter v0.11.0 h1:21xjnqNgxtni2jDgAQ90bl15uDnrTreO9sIlu1YsX/U=
119-
github.com/nginxinc/nginx-prometheus-exporter v0.11.0/go.mod h1:GdyHnWAb8q8OW1Pssrrqbcqra0SH0Vn6UXICMmyWkw8=
120+
github.com/nginxinc/nginx-plus-go-client v1.2.0 h1:NVfRsHbMJ7lOhkqMG52uvODiDBhQZNp20c0tV2lU3wg=
121+
github.com/nginxinc/nginx-plus-go-client v1.2.0/go.mod h1:n8OFLzrJulJ2fur28Cwa1Qp5DZNS2VicLV+Adt30LQ4=
122+
github.com/nginxinc/nginx-prometheus-exporter v1.0.0 h1:rw5q6j6FQe9EWzJy5HzRgRBJ2tSVyC9By6k9ZFQ7lD8=
123+
github.com/nginxinc/nginx-prometheus-exporter v1.0.0/go.mod h1:SPohlKx0SiOuZYi04js53GWWb0HhD281AT8q4ApVMIE=
120124
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
121125
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
122126
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=

internal/mode/static/config_updater.go

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"fmt"
66

77
"github.com/go-logr/logr"
8-
"go.uber.org/zap"
9-
"go.uber.org/zap/zapcore"
108
apiv1 "k8s.io/api/core/v1"
119
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1210
"k8s.io/apimachinery/pkg/types"
@@ -17,54 +15,14 @@ import (
1715
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
1816
)
1917

20-
// ZapLogLevelSetter defines an interface for setting the logging level of a zap logger.
21-
type ZapLogLevelSetter interface {
22-
SetLevel(string) error
23-
Enabled(zapcore.Level) bool
24-
}
25-
26-
type zapSetterImpl struct {
27-
atomicLevel zap.AtomicLevel
28-
}
29-
30-
func newZapLogLevelSetter(atomicLevel zap.AtomicLevel) zapSetterImpl {
31-
return zapSetterImpl{
32-
atomicLevel: atomicLevel,
33-
}
34-
}
35-
36-
// SetLevel sets the logging level for the zap logger.
37-
func (z zapSetterImpl) SetLevel(level string) error {
38-
parsedLevel, err := zapcore.ParseLevel(level)
39-
if err != nil {
40-
fieldErr := field.NotSupported(
41-
field.NewPath("logging.level"),
42-
level,
43-
[]string{
44-
string(ngfAPI.ControllerLogLevelInfo),
45-
string(ngfAPI.ControllerLogLevelDebug),
46-
string(ngfAPI.ControllerLogLevelError),
47-
})
48-
return fieldErr
49-
}
50-
z.atomicLevel.SetLevel(parsedLevel)
51-
52-
return nil
53-
}
54-
55-
// Enabled returns true if the given level is at or above the current level.
56-
func (z zapSetterImpl) Enabled(level zapcore.Level) bool {
57-
return z.atomicLevel.Enabled(level)
58-
}
59-
6018
// updateControlPlane updates the control plane configuration with the given user spec.
6119
// If any fields are not set within the user spec, the default configuration values are used.
6220
func updateControlPlane(
6321
cfg *ngfAPI.NginxGateway,
6422
logger logr.Logger,
6523
eventRecorder record.EventRecorder,
6624
configNSName types.NamespacedName,
67-
logLevelSetter ZapLogLevelSetter,
25+
logLevelSetter logLevelSetter,
6826
) error {
6927
// build up default configuration
7028
controlConfig := ngfAPI.NginxGatewaySpec{
@@ -100,6 +58,36 @@ func updateControlPlane(
10058
)
10159
}
10260

103-
// set the log level
104-
return logLevelSetter.SetLevel(string(*controlConfig.Logging.Level))
61+
level := *controlConfig.Logging.Level
62+
63+
if err := validateLogLevel(level); err != nil {
64+
return err
65+
}
66+
67+
if err := logLevelSetter.SetLevel(string(level)); err != nil {
68+
return field.Invalid(
69+
field.NewPath("logging.level"),
70+
level,
71+
err.Error(),
72+
)
73+
}
74+
75+
return nil
76+
}
77+
78+
func validateLogLevel(level ngfAPI.ControllerLogLevel) error {
79+
switch level {
80+
case ngfAPI.ControllerLogLevelInfo, ngfAPI.ControllerLogLevelDebug, ngfAPI.ControllerLogLevelError:
81+
default:
82+
return field.NotSupported(
83+
field.NewPath("logging.level"),
84+
level,
85+
[]string{
86+
string(ngfAPI.ControllerLogLevelInfo),
87+
string(ngfAPI.ControllerLogLevelDebug),
88+
string(ngfAPI.ControllerLogLevelError),
89+
})
90+
}
91+
92+
return nil
10593
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package static
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"testing"
7+
8+
. "github.com/onsi/gomega"
9+
"k8s.io/apimachinery/pkg/types"
10+
"k8s.io/client-go/tools/record"
11+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
12+
13+
ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
14+
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
15+
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/staticfakes"
16+
)
17+
18+
func TestUpdateControlPlane(t *testing.T) {
19+
debugLogCfg := &ngfAPI.NginxGateway{
20+
Spec: ngfAPI.NginxGatewaySpec{
21+
Logging: &ngfAPI.Logging{
22+
Level: helpers.GetPointer(ngfAPI.ControllerLogLevelDebug),
23+
},
24+
},
25+
}
26+
27+
invalidLevelConfig := &ngfAPI.NginxGateway{
28+
Spec: ngfAPI.NginxGatewaySpec{
29+
Logging: &ngfAPI.Logging{
30+
Level: helpers.GetPointer[ngfAPI.ControllerLogLevel]("invalid"),
31+
},
32+
},
33+
}
34+
35+
logger := zap.New()
36+
fakeEventRecorder := record.NewFakeRecorder(1)
37+
nsname := types.NamespacedName{Namespace: "test", Name: "test"}
38+
39+
tests := []struct {
40+
setLevelErr error
41+
nginxGateway *ngfAPI.NginxGateway
42+
name string
43+
expErrString string
44+
expSetLevelCallCount int
45+
expEvent bool
46+
}{
47+
{
48+
name: "change log level",
49+
nginxGateway: debugLogCfg,
50+
expSetLevelCallCount: 1,
51+
},
52+
{
53+
name: "invalid log level",
54+
nginxGateway: invalidLevelConfig,
55+
expErrString: `Unsupported value: "invalid"`,
56+
expSetLevelCallCount: 0,
57+
},
58+
{
59+
name: "nil NginxGateway",
60+
nginxGateway: nil,
61+
expEvent: true,
62+
expSetLevelCallCount: 1,
63+
},
64+
{
65+
name: "set log level fails",
66+
nginxGateway: debugLogCfg,
67+
setLevelErr: errors.New("set level failed"),
68+
expErrString: "set level failed",
69+
expSetLevelCallCount: 1,
70+
},
71+
}
72+
73+
for _, test := range tests {
74+
t.Run(test.name, func(t *testing.T) {
75+
g := NewWithT(t)
76+
77+
fakeLogSetter := &staticfakes.FakeLogLevelSetter{
78+
SetLevelStub: func(s string) error {
79+
return test.setLevelErr
80+
},
81+
}
82+
83+
err := updateControlPlane(test.nginxGateway, logger, fakeEventRecorder, nsname, fakeLogSetter)
84+
85+
if test.expErrString != "" {
86+
g.Expect(err).To(HaveOccurred())
87+
g.Expect(err.Error()).To(ContainSubstring(test.expErrString))
88+
} else {
89+
g.Expect(err).ToNot(HaveOccurred())
90+
}
91+
92+
if test.expEvent {
93+
g.Expect(fakeEventRecorder.Events).To(HaveLen(1))
94+
event := <-fakeEventRecorder.Events
95+
g.Expect(event).To(ContainSubstring("ResourceDeleted"))
96+
} else {
97+
g.Expect(fakeEventRecorder.Events).To(BeEmpty())
98+
}
99+
100+
g.Expect(fakeLogSetter.SetLevelCallCount()).To(Equal(test.expSetLevelCallCount))
101+
})
102+
}
103+
}
104+
105+
func TestValidateLogLevel(t *testing.T) {
106+
validLevels := []ngfAPI.ControllerLogLevel{
107+
ngfAPI.ControllerLogLevelError,
108+
ngfAPI.ControllerLogLevelInfo,
109+
ngfAPI.ControllerLogLevelDebug,
110+
}
111+
112+
invalidLevels := []ngfAPI.ControllerLogLevel{
113+
ngfAPI.ControllerLogLevel("invalid"),
114+
ngfAPI.ControllerLogLevel("high"),
115+
ngfAPI.ControllerLogLevel("warn"),
116+
}
117+
118+
for _, level := range validLevels {
119+
t.Run(fmt.Sprintf("valid level %q", level), func(t *testing.T) {
120+
g := NewWithT(t)
121+
122+
g.Expect(validateLogLevel(level)).To(Succeed())
123+
})
124+
}
125+
126+
for _, level := range invalidLevels {
127+
t.Run(fmt.Sprintf("invalid level %q", level), func(t *testing.T) {
128+
g := NewWithT(t)
129+
130+
g.Expect(validateLogLevel(level)).ToNot(Succeed())
131+
})
132+
}
133+
}

internal/mode/static/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ type eventHandlerConfig struct {
5454
// eventRecorder records events for Kubernetes resources.
5555
eventRecorder record.EventRecorder
5656
// logLevelSetter is used to update the logging level.
57-
logLevelSetter ZapLogLevelSetter
57+
logLevelSetter logLevelSetter
5858
// metricsCollector collects metrics for this controller.
5959
metricsCollector handlerMetricsCollector
6060
// healthChecker sets the health of the Pod to Ready once we've written out our initial config

internal/mode/static/handler_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ var _ = Describe("eventHandler", func() {
4444
fakeEventRecorder *record.FakeRecorder
4545
namespace = "nginx-gateway"
4646
configName = "nginx-gateway-config"
47+
zapLogLevelSetter zapLogLevelSetter
4748
)
4849

4950
expectReconfig := func(expectedConf dataplane.Configuration, expectedFiles []file.File) {
@@ -68,12 +69,13 @@ var _ = Describe("eventHandler", func() {
6869
fakeNginxRuntimeMgr = &runtimefakes.FakeManager{}
6970
fakeStatusUpdater = &statusfakes.FakeUpdater{}
7071
fakeEventRecorder = record.NewFakeRecorder(1)
72+
zapLogLevelSetter = newZapLogLevelSetter(zap.NewAtomicLevel())
7173

7274
handler = newEventHandlerImpl(eventHandlerConfig{
7375
k8sClient: fake.NewFakeClient(),
7476
processor: fakeProcessor,
7577
generator: fakeGenerator,
76-
logLevelSetter: newZapLogLevelSetter(zap.NewAtomicLevel()),
78+
logLevelSetter: zapLogLevelSetter,
7779
nginxFileMgr: fakeNginxFileMgr,
7880
nginxRuntimeMgr: fakeNginxRuntimeMgr,
7981
statusUpdater: fakeStatusUpdater,
@@ -196,8 +198,8 @@ var _ = Describe("eventHandler", func() {
196198
Expect(fakeStatusUpdater.UpdateCallCount()).Should(Equal(1))
197199
_, statuses := fakeStatusUpdater.UpdateArgsForCall(0)
198200
Expect(statuses).To(Equal(expStatuses(staticConds.NewNginxGatewayValid())))
199-
Expect(handler.cfg.logLevelSetter.Enabled(zap.DebugLevel)).To(BeFalse())
200-
Expect(handler.cfg.logLevelSetter.Enabled(zap.ErrorLevel)).To(BeTrue())
201+
Expect(zapLogLevelSetter.Enabled(zap.DebugLevel)).To(BeFalse())
202+
Expect(zapLogLevelSetter.Enabled(zap.ErrorLevel)).To(BeTrue())
201203
})
202204

203205
It("handles an invalid config", func() {
@@ -216,7 +218,7 @@ var _ = Describe("eventHandler", func() {
216218
"Warning UpdateFailed Failed to update control plane configuration: logging.level: Unsupported value: " +
217219
"\"invalid\": supported values: \"info\", \"debug\", \"error\"",
218220
))
219-
Expect(handler.cfg.logLevelSetter.Enabled(zap.InfoLevel)).To(BeTrue())
221+
Expect(zapLogLevelSetter.Enabled(zap.InfoLevel)).To(BeTrue())
220222
})
221223

222224
It("handles a deleted config", func() {
@@ -225,7 +227,7 @@ var _ = Describe("eventHandler", func() {
225227
Expect(len(fakeEventRecorder.Events)).To(Equal(1))
226228
event := <-fakeEventRecorder.Events
227229
Expect(event).To(Equal("Warning ResourceDeleted NginxGateway configuration was deleted; using defaults"))
228-
Expect(handler.cfg.logLevelSetter.Enabled(zap.InfoLevel)).To(BeTrue())
230+
Expect(zapLogLevelSetter.Enabled(zap.InfoLevel)).To(BeTrue())
229231
})
230232
})
231233

0 commit comments

Comments
 (0)