Skip to content

Commit a8805b2

Browse files
committed
test: testcases and minor fix
Signed-off-by: STRRL <[email protected]>
1 parent 6078881 commit a8805b2

File tree

4 files changed

+252
-29
lines changed

4 files changed

+252
-29
lines changed

pkg/log/logr/kube_aware_logger_sink.go

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,57 @@ import (
2424
)
2525

2626
type KubeAwareLogSink struct {
27+
sink logr.LogSink
2728
kubeAwareEnabled *atomic.Bool
28-
logger logr.LogSink
29+
}
30+
31+
func NewKubeAwareLogger(logger logr.Logger, kubeAwareEnabled bool) logr.Logger {
32+
return logr.New(NewKubeAwareLogSink(logger.GetSink(), kubeAwareEnabled))
33+
}
34+
35+
func NewKubeAwareLogSink(logSink logr.LogSink, kubeAwareEnabled bool) *KubeAwareLogSink {
36+
return &KubeAwareLogSink{sink: logSink, kubeAwareEnabled: atomic.NewBool(kubeAwareEnabled)}
2937
}
3038

3139
func (k *KubeAwareLogSink) Init(info logr.RuntimeInfo) {
32-
k.logger.Init(info)
40+
k.sink.Init(info)
3341
}
3442

3543
func (k *KubeAwareLogSink) Enabled(level int) bool {
36-
return k.logger.Enabled(level)
44+
return k.sink.Enabled(level)
3745
}
3846

3947
func (k *KubeAwareLogSink) Info(level int, msg string, keysAndValues ...interface{}) {
4048
if !k.KubeAwareEnabled() {
41-
k.logger.Info(level, msg, keysAndValues...)
49+
k.sink.Info(level, msg, keysAndValues...)
4250
return
4351
}
4452

45-
k.logger.Info(level, msg, k.wrapKeyAndValues(keysAndValues)...)
53+
k.sink.Info(level, msg, k.wrapKeyAndValues(keysAndValues)...)
4654
}
4755

4856
func (k *KubeAwareLogSink) Error(err error, msg string, keysAndValues ...interface{}) {
4957
if !k.KubeAwareEnabled() {
50-
k.logger.Error(err, msg, keysAndValues...)
58+
k.sink.Error(err, msg, keysAndValues...)
5159
return
5260
}
53-
k.logger.Error(err, msg, k.wrapKeyAndValues(keysAndValues)...)
61+
k.sink.Error(err, msg, k.wrapKeyAndValues(keysAndValues)...)
5462
}
5563

5664
func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []interface{} {
5765
result := make([]interface{}, len(keysAndValues))
5866
for i, item := range keysAndValues {
59-
if i%2 == 1 {
67+
if i%2 == 0 {
6068
// item is key, no need to resolve
6169
result[i] = item
6270
continue
6371
}
72+
6473
switch val := item.(type) {
6574
case runtime.Object:
66-
result[i] = kubeObjectWrapper{obj: val}
75+
result[i] = &kubeObjectWrapper{obj: val}
6776
case types.NamespacedName:
68-
result[i] = namespacedNameWrapper{NamespacedName: val}
77+
result[i] = &namespacedNameWrapper{NamespacedName: val}
6978
default:
7079
result[i] = item
7180
}
@@ -76,14 +85,14 @@ func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []inter
7685
func (k *KubeAwareLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink {
7786
return &KubeAwareLogSink{
7887
kubeAwareEnabled: k.kubeAwareEnabled,
79-
logger: k.logger.WithValues(keysAndValues...),
88+
sink: k.sink.WithValues(k.wrapKeyAndValues(keysAndValues)...),
8089
}
8190
}
8291

8392
func (k *KubeAwareLogSink) WithName(name string) logr.LogSink {
8493
return &KubeAwareLogSink{
8594
kubeAwareEnabled: k.kubeAwareEnabled,
86-
logger: k.logger.WithName(name),
95+
sink: k.sink.WithName(name),
8796
}
8897
}
8998

pkg/log/logr/kube_aware_logger_sink_test.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

pkg/log/logr/kube_object_wrapper.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package logr
1919
import (
2020
"k8s.io/apimachinery/pkg/api/meta"
2121
"k8s.io/apimachinery/pkg/runtime"
22+
"reflect"
2223
)
2324

2425
type kubeObjectWrapper struct {
@@ -27,6 +28,12 @@ type kubeObjectWrapper struct {
2728

2829
func (w *kubeObjectWrapper) MarshalLog() interface{} {
2930
result := make(map[string]string)
31+
32+
if reflect.ValueOf(w.obj).IsNil() {
33+
// best effort ,noop
34+
return nil
35+
}
36+
3037
if gvk := w.obj.GetObjectKind().GroupVersionKind(); gvk.Version != "" {
3138
result["apiVersion"] = gvk.GroupVersion().String()
3239
result["kind"] = gvk.Kind

pkg/log/logr/logr_test.go

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package logr
18+
19+
import (
20+
"bytes"
21+
"encoding/json"
22+
"github.com/go-logr/logr"
23+
. "github.com/onsi/ginkgo"
24+
. "github.com/onsi/gomega"
25+
corev1 "k8s.io/api/core/v1"
26+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
27+
"k8s.io/apimachinery/pkg/types"
28+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
29+
)
30+
31+
// testStringer is a fmt.Stringer.
32+
type testStringer struct{}
33+
34+
func (testStringer) String() string {
35+
return "value"
36+
}
37+
38+
var _ = Describe("Logr logSink setup", func() {
39+
40+
Context("when logging kubernetes objects", func() {
41+
var logOut *bytes.Buffer
42+
var zaplogger logr.Logger
43+
var logger logr.Logger
44+
45+
Context("with logger created using zap.New", func() {
46+
BeforeEach(func() {
47+
logOut = new(bytes.Buffer)
48+
By("setting up the logger")
49+
// use production settings (false) to get just json output
50+
zaplogger = zap.New(zap.WriteTo(logOut), zap.UseDevMode(false))
51+
logger = NewKubeAwareLogger(zaplogger, true)
52+
53+
})
54+
55+
It("should log a standard namespaced Kubernetes object name and namespace", func() {
56+
pod := &corev1.Pod{}
57+
pod.Name = "some-pod"
58+
pod.Namespace = "some-ns"
59+
logger.Info("here's a kubernetes object", "thing", pod)
60+
61+
outRaw := logOut.Bytes()
62+
res := map[string]interface{}{}
63+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
64+
65+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
66+
"name": pod.Name,
67+
"namespace": pod.Namespace,
68+
}))
69+
})
70+
71+
It("should work fine with normal stringers", func() {
72+
logger.Info("here's a non-kubernetes stringer", "thing", testStringer{})
73+
outRaw := logOut.Bytes()
74+
res := map[string]interface{}{}
75+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
76+
77+
Expect(res).To(HaveKeyWithValue("thing", "value"))
78+
})
79+
80+
It("should log a standard non-namespaced Kubernetes object name", func() {
81+
node := &corev1.Node{}
82+
node.Name = "some-node"
83+
logger.Info("here's a kubernetes object", "thing", node)
84+
85+
outRaw := logOut.Bytes()
86+
res := map[string]interface{}{}
87+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
88+
89+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
90+
"name": node.Name,
91+
}))
92+
})
93+
94+
It("should log a standard Kubernetes object's kind, if set", func() {
95+
node := &corev1.Node{}
96+
node.Name = "some-node"
97+
node.APIVersion = "v1"
98+
node.Kind = "Node"
99+
logger.Info("here's a kubernetes object", "thing", node)
100+
101+
outRaw := logOut.Bytes()
102+
res := map[string]interface{}{}
103+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
104+
105+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
106+
"name": node.Name,
107+
"apiVersion": "v1",
108+
"kind": "Node",
109+
}))
110+
})
111+
112+
It("should log a standard non-namespaced NamespacedName name", func() {
113+
name := types.NamespacedName{Name: "some-node"}
114+
logger.Info("here's a kubernetes object", "thing", name)
115+
116+
outRaw := logOut.Bytes()
117+
res := map[string]interface{}{}
118+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
119+
120+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
121+
"name": name.Name,
122+
}))
123+
})
124+
125+
It("should log an unstructured Kubernetes object", func() {
126+
pod := &unstructured.Unstructured{
127+
Object: map[string]interface{}{
128+
"metadata": map[string]interface{}{
129+
"name": "some-pod",
130+
"namespace": "some-ns",
131+
},
132+
},
133+
}
134+
logger.Info("here's a kubernetes object", "thing", pod)
135+
136+
outRaw := logOut.Bytes()
137+
res := map[string]interface{}{}
138+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
139+
140+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
141+
"name": "some-pod",
142+
"namespace": "some-ns",
143+
}))
144+
})
145+
146+
It("should log a standard namespaced NamespacedName name and namespace", func() {
147+
name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"}
148+
logger.Info("here's a kubernetes object", "thing", name)
149+
150+
outRaw := logOut.Bytes()
151+
res := map[string]interface{}{}
152+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
153+
154+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
155+
"name": name.Name,
156+
"namespace": name.Namespace,
157+
}))
158+
})
159+
160+
It("should not panic with nil obj", func() {
161+
var pod *corev1.Pod
162+
logger.Info("here's a kubernetes object", "thing", pod)
163+
outRaw := logOut.Bytes()
164+
res := map[string]interface{}{}
165+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
166+
Expect(res).To(HaveKey("thing"))
167+
Expect(res["things"]).To(BeNil())
168+
})
169+
170+
It("should log a standard namespaced when using logrLogger.WithValues", func() {
171+
name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"}
172+
logger.WithValues("thing", name).Info("here's a kubernetes object")
173+
174+
outRaw := logOut.Bytes()
175+
res := map[string]interface{}{}
176+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
177+
178+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
179+
"name": name.Name,
180+
"namespace": name.Namespace,
181+
}))
182+
})
183+
184+
It("should log a standard Kubernetes objects when using logrLogger.WithValues", func() {
185+
node := &corev1.Node{}
186+
node.Name = "some-node"
187+
node.APIVersion = "v1"
188+
node.Kind = "Node"
189+
logger.WithValues("thing", node).Info("here's a kubernetes object")
190+
191+
outRaw := logOut.Bytes()
192+
res := map[string]interface{}{}
193+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
194+
195+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
196+
"name": node.Name,
197+
"apiVersion": "v1",
198+
"kind": "Node",
199+
}))
200+
})
201+
202+
It("should log a standard unstructured Kubernetes object when using logrLogger.WithValues", func() {
203+
pod := &unstructured.Unstructured{
204+
Object: map[string]interface{}{
205+
"metadata": map[string]interface{}{
206+
"name": "some-pod",
207+
"namespace": "some-ns",
208+
},
209+
},
210+
}
211+
logger.WithValues("thing", pod).Info("here's a kubernetes object")
212+
213+
outRaw := logOut.Bytes()
214+
res := map[string]interface{}{}
215+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
216+
217+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
218+
"name": "some-pod",
219+
"namespace": "some-ns",
220+
}))
221+
})
222+
})
223+
})
224+
})

0 commit comments

Comments
 (0)