From dad2a29852e3c9759237cfa74e2f03bf3a3f7c1b Mon Sep 17 00:00:00 2001 From: STRRL Date: Tue, 3 May 2022 15:37:29 +0800 Subject: [PATCH 1/8] test: testcases for zap logger with WithValues() to introduce the expected behavior with KubeAwareEncoder Signed-off-by: STRRL --- pkg/log/zap/zap_test.go | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/pkg/log/zap/zap_test.go b/pkg/log/zap/zap_test.go index 2d18476e1f..06fbff4ce0 100644 --- a/pkg/log/zap/zap_test.go +++ b/pkg/log/zap/zap_test.go @@ -263,6 +263,65 @@ var _ = Describe("Zap logger setup", func() { outRaw := logOut.Bytes() Expect(string(outRaw)).Should(ContainSubstring("got nil for runtime.Object")) }) + + // see https://github.com/kubernetes-sigs/controller-runtime/issues/1290 + It("should log NamespacedName as origin stringer when using logrLogger.WithValues", func() { + name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"} + logger.WithValues("thing", name).Info("here's a kubernetes object") + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).NotTo(HaveKeyWithValue("thing", map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + })) + Expect(res).To(HaveKeyWithValue("thing", "some-ns/some-pod")) + }) + + // see https://github.com/kubernetes-sigs/controller-runtime/issues/1290 + It("should log Kubernetes objects as origin stringer when using logrLogger.WithValues", func() { + node := &corev1.Node{} + node.Name = "some-node" + node.APIVersion = "v1" + node.Kind = "Node" + logger.WithValues("thing", node).Info("here's a kubernetes object") + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).NotTo(HaveKeyWithValue("thing", map[string]interface{}{ + "name": node.Name, + "apiVersion": "v1", + "kind": "Node", + })) + Expect(res).To(HaveKeyWithValue("thing", "&Node{ObjectMeta:{some-node 0 0001-01-01 00:00:00 +0000 UTC map[] map[] [] [] []},Spec:NodeSpec{PodCIDR:,DoNotUseExternalID:,ProviderID:,Unschedulable:false,Taints:[]Taint{},ConfigSource:nil,PodCIDRs:[],},Status:NodeStatus{Capacity:ResourceList{},Allocatable:ResourceList{},Phase:,Conditions:[]NodeCondition{},Addresses:[]NodeAddress{},DaemonEndpoints:NodeDaemonEndpoints{KubeletEndpoint:DaemonEndpoint{Port:0,},},NodeInfo:NodeSystemInfo{MachineID:,SystemUUID:,BootID:,KernelVersion:,OSImage:,ContainerRuntimeVersion:,KubeletVersion:,KubeProxyVersion:,OperatingSystem:,Architecture:,},Images:[]ContainerImage{},VolumesInUse:[],VolumesAttached:[]AttachedVolume{},Config:nil,},}")) + }) + + // see https://github.com/kubernetes-sigs/controller-runtime/issues/1290 + It("should log an unstructured Kubernetes object as origin stringer when using logrLogger.WithValues", func() { + pod := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "some-pod", + "namespace": "some-ns", + }, + }, + } + logger.WithValues("thing", pod).Info("here's a kubernetes object") + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).NotTo(HaveKeyWithValue("thing", map[string]interface{}{ + "name": "some-pod", + "namespace": "some-ns", + })) + Expect(res).To(HaveKeyWithValue("thing", pod.Object)) + }) } Context("with logger created using New", func() { From 55e5026a4243184240d85a55c46a010d5cc2bce6 Mon Sep 17 00:00:00 2001 From: STRRL Date: Tue, 3 May 2022 16:15:05 +0800 Subject: [PATCH 2/8] chore: new option to enable KubeAwareEncoder Signed-off-by: STRRL --- pkg/log/zap/zap.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/log/zap/zap.go b/pkg/log/zap/zap.go index 7db4cdda39..71cdc4ae01 100644 --- a/pkg/log/zap/zap.go +++ b/pkg/log/zap/zap.go @@ -170,6 +170,11 @@ type Options struct { // TimeEncoder specifies the encoder for the timestamps in log messages. // Defaults to EpochTimeEncoder as this is the default in Zap currently. TimeEncoder zapcore.TimeEncoder + // UseKubeAwareEncoder configures the logger to use the KubeAwareEncoder for encoding kubernetes + // object as Type information and Namespace/Name. + // Note: KubeAwareEncoder could NOT resolve the object passed by logger.WithValues(), see + // https://github.com/kubernetes-sigs/controller-runtime/issues/1290 + UseKubeAwareEncoder bool } // addDefaults adds defaults to the Options. @@ -245,7 +250,11 @@ func NewRaw(opts ...Opts) *zap.Logger { sink := zapcore.AddSync(o.DestWriter) o.ZapOpts = append(o.ZapOpts, zap.AddCallerSkip(1), zap.ErrorOutput(sink)) - log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development}, sink, o.Level)) + encoder := o.Encoder + if o.UseKubeAwareEncoder { + encoder = &KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development} + } + log := zap.New(zapcore.NewCore(encoder, sink, o.Level)) log = log.WithOptions(o.ZapOpts...) return log } From 20e4afa59a95af6fe907826c34389c026d61c9a9 Mon Sep 17 00:00:00 2001 From: STRRL Date: Tue, 3 May 2022 17:18:05 +0800 Subject: [PATCH 3/8] chore: basic implementation Signed-off-by: STRRL --- pkg/log/logr/doc.go | 19 ++++ pkg/log/logr/kube_aware_logger_sink.go | 96 +++++++++++++++++++++ pkg/log/logr/kube_aware_logger_sink_test.go | 17 ++++ pkg/log/logr/kube_object_wrapper.go | 46 ++++++++++ pkg/log/logr/logr_suite_test.go | 31 +++++++ pkg/log/logr/namespaced_name_wrapper.go | 32 +++++++ 6 files changed, 241 insertions(+) create mode 100644 pkg/log/logr/doc.go create mode 100644 pkg/log/logr/kube_aware_logger_sink.go create mode 100644 pkg/log/logr/kube_aware_logger_sink_test.go create mode 100644 pkg/log/logr/kube_object_wrapper.go create mode 100644 pkg/log/logr/logr_suite_test.go create mode 100644 pkg/log/logr/namespaced_name_wrapper.go diff --git a/pkg/log/logr/doc.go b/pkg/log/logr/doc.go new file mode 100644 index 0000000000..6f955300bb --- /dev/null +++ b/pkg/log/logr/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package logr introduces an implementation of logr.LogSink, which could +// encode Kubernetes Objects into Type information and Namespace/Name. +package logr diff --git a/pkg/log/logr/kube_aware_logger_sink.go b/pkg/log/logr/kube_aware_logger_sink.go new file mode 100644 index 0000000000..a2d9bef545 --- /dev/null +++ b/pkg/log/logr/kube_aware_logger_sink.go @@ -0,0 +1,96 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package logr + +import ( + "github.com/go-logr/logr" + "go.uber.org/atomic" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" +) + +type KubeAwareLogSink struct { + kubeAwareEnabled *atomic.Bool + logger logr.LogSink +} + +func (k *KubeAwareLogSink) Init(info logr.RuntimeInfo) { + k.logger.Init(info) +} + +func (k *KubeAwareLogSink) Enabled(level int) bool { + return k.logger.Enabled(level) +} + +func (k *KubeAwareLogSink) Info(level int, msg string, keysAndValues ...interface{}) { + if !k.KubeAwareEnabled() { + k.logger.Info(level, msg, keysAndValues...) + return + } + + k.logger.Info(level, msg, k.wrapKeyAndValues(keysAndValues)...) +} + +func (k *KubeAwareLogSink) Error(err error, msg string, keysAndValues ...interface{}) { + if !k.KubeAwareEnabled() { + k.logger.Error(err, msg, keysAndValues...) + return + } + k.logger.Error(err, msg, k.wrapKeyAndValues(keysAndValues)...) +} + +func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []interface{} { + result := make([]interface{}, len(keysAndValues)) + for i, item := range keysAndValues { + if i%2 == 1 { + // item is key, no need to resolve + result[i] = item + continue + } + switch val := item.(type) { + case runtime.Object: + result[i] = kubeObjectWrapper{obj: val} + case types.NamespacedName: + result[i] = namespacedNameWrapper{NamespacedName: val} + default: + result[i] = item + } + } + return result +} + +func (k *KubeAwareLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { + return &KubeAwareLogSink{ + kubeAwareEnabled: k.kubeAwareEnabled, + logger: k.logger.WithValues(keysAndValues...), + } +} + +func (k *KubeAwareLogSink) WithName(name string) logr.LogSink { + return &KubeAwareLogSink{ + kubeAwareEnabled: k.kubeAwareEnabled, + logger: k.logger.WithName(name), + } +} + +func (k *KubeAwareLogSink) KubeAwareEnabled() bool { + return k.kubeAwareEnabled.Load() +} + +func (k *KubeAwareLogSink) SetKubeAwareEnabled(enabled bool) { + k.kubeAwareEnabled.Store(enabled) +} diff --git a/pkg/log/logr/kube_aware_logger_sink_test.go b/pkg/log/logr/kube_aware_logger_sink_test.go new file mode 100644 index 0000000000..ff1f74bb7c --- /dev/null +++ b/pkg/log/logr/kube_aware_logger_sink_test.go @@ -0,0 +1,17 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package logr diff --git a/pkg/log/logr/kube_object_wrapper.go b/pkg/log/logr/kube_object_wrapper.go new file mode 100644 index 0000000000..b7f7381f9a --- /dev/null +++ b/pkg/log/logr/kube_object_wrapper.go @@ -0,0 +1,46 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package logr + +import ( + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" +) + +type kubeObjectWrapper struct { + obj runtime.Object +} + +func (w *kubeObjectWrapper) MarshalLog() interface{} { + result := make(map[string]string) + if gvk := w.obj.GetObjectKind().GroupVersionKind(); gvk.Version != "" { + result["apiVersion"] = gvk.GroupVersion().String() + result["kind"] = gvk.Kind + } + + objMeta, err := meta.Accessor(w.obj) + if err != nil { + // best effort, noop + return result + } + + if ns := objMeta.GetNamespace(); ns != "" { + result["namespace"] = ns + } + result["name"] = objMeta.GetName() + return result +} diff --git a/pkg/log/logr/logr_suite_test.go b/pkg/log/logr/logr_suite_test.go new file mode 100644 index 0000000000..64bf783069 --- /dev/null +++ b/pkg/log/logr/logr_suite_test.go @@ -0,0 +1,31 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package logr + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" +) + +func TestSource(t *testing.T) { + RegisterFailHandler(Fail) + suiteName := "Logr Log Suite" + RunSpecsWithDefaultAndCustomReporters(t, suiteName, []Reporter{printer.NewlineReporter{}, printer.NewProwReporter(suiteName)}) +} diff --git a/pkg/log/logr/namespaced_name_wrapper.go b/pkg/log/logr/namespaced_name_wrapper.go new file mode 100644 index 0000000000..89c12cd512 --- /dev/null +++ b/pkg/log/logr/namespaced_name_wrapper.go @@ -0,0 +1,32 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package logr + +import "k8s.io/apimachinery/pkg/types" + +type namespacedNameWrapper struct { + types.NamespacedName +} + +func (w *namespacedNameWrapper) MarshalLog() interface{} { + result := make(map[string]string) + if w.Namespace != "" { + result["namespace"] = w.Namespace + } + result["name"] = w.Name + return result +} From a863a3b4bb4c23fc088adeba8e79ba6874d926bb Mon Sep 17 00:00:00 2001 From: STRRL Date: Tue, 3 May 2022 18:04:22 +0800 Subject: [PATCH 4/8] test: testcases and minor fix Signed-off-by: STRRL --- pkg/log/logr/kube_aware_logger_sink.go | 33 +-- pkg/log/logr/kube_aware_logger_sink_test.go | 17 -- pkg/log/logr/kube_object_wrapper.go | 7 + pkg/log/logr/logr_test.go | 224 ++++++++++++++++++++ 4 files changed, 252 insertions(+), 29 deletions(-) delete mode 100644 pkg/log/logr/kube_aware_logger_sink_test.go create mode 100644 pkg/log/logr/logr_test.go diff --git a/pkg/log/logr/kube_aware_logger_sink.go b/pkg/log/logr/kube_aware_logger_sink.go index a2d9bef545..908a9b20b1 100644 --- a/pkg/log/logr/kube_aware_logger_sink.go +++ b/pkg/log/logr/kube_aware_logger_sink.go @@ -24,48 +24,57 @@ import ( ) type KubeAwareLogSink struct { + sink logr.LogSink kubeAwareEnabled *atomic.Bool - logger logr.LogSink +} + +func NewKubeAwareLogger(logger logr.Logger, kubeAwareEnabled bool) logr.Logger { + return logr.New(NewKubeAwareLogSink(logger.GetSink(), kubeAwareEnabled)) +} + +func NewKubeAwareLogSink(logSink logr.LogSink, kubeAwareEnabled bool) *KubeAwareLogSink { + return &KubeAwareLogSink{sink: logSink, kubeAwareEnabled: atomic.NewBool(kubeAwareEnabled)} } func (k *KubeAwareLogSink) Init(info logr.RuntimeInfo) { - k.logger.Init(info) + k.sink.Init(info) } func (k *KubeAwareLogSink) Enabled(level int) bool { - return k.logger.Enabled(level) + return k.sink.Enabled(level) } func (k *KubeAwareLogSink) Info(level int, msg string, keysAndValues ...interface{}) { if !k.KubeAwareEnabled() { - k.logger.Info(level, msg, keysAndValues...) + k.sink.Info(level, msg, keysAndValues...) return } - k.logger.Info(level, msg, k.wrapKeyAndValues(keysAndValues)...) + k.sink.Info(level, msg, k.wrapKeyAndValues(keysAndValues)...) } func (k *KubeAwareLogSink) Error(err error, msg string, keysAndValues ...interface{}) { if !k.KubeAwareEnabled() { - k.logger.Error(err, msg, keysAndValues...) + k.sink.Error(err, msg, keysAndValues...) return } - k.logger.Error(err, msg, k.wrapKeyAndValues(keysAndValues)...) + k.sink.Error(err, msg, k.wrapKeyAndValues(keysAndValues)...) } func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []interface{} { result := make([]interface{}, len(keysAndValues)) for i, item := range keysAndValues { - if i%2 == 1 { + if i%2 == 0 { // item is key, no need to resolve result[i] = item continue } + switch val := item.(type) { case runtime.Object: - result[i] = kubeObjectWrapper{obj: val} + result[i] = &kubeObjectWrapper{obj: val} case types.NamespacedName: - result[i] = namespacedNameWrapper{NamespacedName: val} + result[i] = &namespacedNameWrapper{NamespacedName: val} default: result[i] = item } @@ -76,14 +85,14 @@ func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []inter func (k *KubeAwareLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { return &KubeAwareLogSink{ kubeAwareEnabled: k.kubeAwareEnabled, - logger: k.logger.WithValues(keysAndValues...), + sink: k.sink.WithValues(k.wrapKeyAndValues(keysAndValues)...), } } func (k *KubeAwareLogSink) WithName(name string) logr.LogSink { return &KubeAwareLogSink{ kubeAwareEnabled: k.kubeAwareEnabled, - logger: k.logger.WithName(name), + sink: k.sink.WithName(name), } } diff --git a/pkg/log/logr/kube_aware_logger_sink_test.go b/pkg/log/logr/kube_aware_logger_sink_test.go deleted file mode 100644 index ff1f74bb7c..0000000000 --- a/pkg/log/logr/kube_aware_logger_sink_test.go +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2022 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package logr diff --git a/pkg/log/logr/kube_object_wrapper.go b/pkg/log/logr/kube_object_wrapper.go index b7f7381f9a..ee964fef99 100644 --- a/pkg/log/logr/kube_object_wrapper.go +++ b/pkg/log/logr/kube_object_wrapper.go @@ -19,6 +19,7 @@ package logr import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" + "reflect" ) type kubeObjectWrapper struct { @@ -27,6 +28,12 @@ type kubeObjectWrapper struct { func (w *kubeObjectWrapper) MarshalLog() interface{} { result := make(map[string]string) + + if reflect.ValueOf(w.obj).IsNil() { + // best effort ,noop + return nil + } + if gvk := w.obj.GetObjectKind().GroupVersionKind(); gvk.Version != "" { result["apiVersion"] = gvk.GroupVersion().String() result["kind"] = gvk.Kind diff --git a/pkg/log/logr/logr_test.go b/pkg/log/logr/logr_test.go new file mode 100644 index 0000000000..270d715622 --- /dev/null +++ b/pkg/log/logr/logr_test.go @@ -0,0 +1,224 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package logr + +import ( + "bytes" + "encoding/json" + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +// testStringer is a fmt.Stringer. +type testStringer struct{} + +func (testStringer) String() string { + return "value" +} + +var _ = Describe("Logr logSink setup", func() { + + Context("when logging kubernetes objects", func() { + var logOut *bytes.Buffer + var zaplogger logr.Logger + var logger logr.Logger + + Context("with logger created using zap.New", func() { + BeforeEach(func() { + logOut = new(bytes.Buffer) + By("setting up the logger") + // use production settings (false) to get just json output + zaplogger = zap.New(zap.WriteTo(logOut), zap.UseDevMode(false)) + logger = NewKubeAwareLogger(zaplogger, true) + + }) + + It("should log a standard namespaced Kubernetes object name and namespace", func() { + pod := &corev1.Pod{} + pod.Name = "some-pod" + pod.Namespace = "some-ns" + logger.Info("here's a kubernetes object", "thing", pod) + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": pod.Name, + "namespace": pod.Namespace, + })) + }) + + It("should work fine with normal stringers", func() { + logger.Info("here's a non-kubernetes stringer", "thing", testStringer{}) + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", "value")) + }) + + It("should log a standard non-namespaced Kubernetes object name", func() { + node := &corev1.Node{} + node.Name = "some-node" + logger.Info("here's a kubernetes object", "thing", node) + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": node.Name, + })) + }) + + It("should log a standard Kubernetes object's kind, if set", func() { + node := &corev1.Node{} + node.Name = "some-node" + node.APIVersion = "v1" + node.Kind = "Node" + logger.Info("here's a kubernetes object", "thing", node) + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": node.Name, + "apiVersion": "v1", + "kind": "Node", + })) + }) + + It("should log a standard non-namespaced NamespacedName name", func() { + name := types.NamespacedName{Name: "some-node"} + logger.Info("here's a kubernetes object", "thing", name) + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": name.Name, + })) + }) + + It("should log an unstructured Kubernetes object", func() { + pod := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "some-pod", + "namespace": "some-ns", + }, + }, + } + logger.Info("here's a kubernetes object", "thing", pod) + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": "some-pod", + "namespace": "some-ns", + })) + }) + + It("should log a standard namespaced NamespacedName name and namespace", func() { + name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"} + logger.Info("here's a kubernetes object", "thing", name) + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + })) + }) + + It("should not panic with nil obj", func() { + var pod *corev1.Pod + logger.Info("here's a kubernetes object", "thing", pod) + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + Expect(res).To(HaveKey("thing")) + Expect(res["things"]).To(BeNil()) + }) + + It("should log a standard namespaced when using logrLogger.WithValues", func() { + name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"} + logger.WithValues("thing", name).Info("here's a kubernetes object") + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + })) + }) + + It("should log a standard Kubernetes objects when using logrLogger.WithValues", func() { + node := &corev1.Node{} + node.Name = "some-node" + node.APIVersion = "v1" + node.Kind = "Node" + logger.WithValues("thing", node).Info("here's a kubernetes object") + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": node.Name, + "apiVersion": "v1", + "kind": "Node", + })) + }) + + It("should log a standard unstructured Kubernetes object when using logrLogger.WithValues", func() { + pod := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": "some-pod", + "namespace": "some-ns", + }, + }, + } + logger.WithValues("thing", pod).Info("here's a kubernetes object") + + outRaw := logOut.Bytes() + res := map[string]interface{}{} + Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) + + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ + "name": "some-pod", + "namespace": "some-ns", + })) + }) + }) + }) +}) From c2880521f6517df76c315757097300cb5607efc3 Mon Sep 17 00:00:00 2001 From: STRRL Date: Tue, 3 May 2022 18:32:37 +0800 Subject: [PATCH 5/8] chore: replace zap.New with bootstrap.New Signed-off-by: STRRL --- examples/builtins/main.go | 4 +- examples/configfile/builtin/main.go | 4 +- examples/configfile/custom/main.go | 4 +- examples/crd/main.go | 4 +- examples/scratch-env/main.go | 3 +- examples/tokenreview/main.go | 4 +- pkg/log/bootstrap/doc.go | 18 +++++++ pkg/log/bootstrap/log.go | 37 +++++++++++++++ pkg/log/logr/kube_aware_logger_sink.go | 62 ++++++++++++++++--------- pkg/log/logr/kube_object_wrapper.go | 6 ++- pkg/log/logr/logr_test.go | 8 ++-- pkg/log/logr/namespaced_name_wrapper.go | 7 ++- pkg/log/zap/zap.go | 1 + pkg/log/zap/zap_test.go | 6 +-- 14 files changed, 128 insertions(+), 40 deletions(-) create mode 100644 pkg/log/bootstrap/doc.go create mode 100644 pkg/log/bootstrap/log.go diff --git a/examples/builtins/main.go b/examples/builtins/main.go index ff1f0dfa3b..44ef212575 100644 --- a/examples/builtins/main.go +++ b/examples/builtins/main.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/source" @@ -34,7 +34,7 @@ import ( ) func init() { - log.SetLogger(zap.New()) + log.SetLogger(bootstrap.New()) } func main() { diff --git a/examples/configfile/builtin/main.go b/examples/configfile/builtin/main.go index abd6180d19..793755a1f2 100644 --- a/examples/configfile/builtin/main.go +++ b/examples/configfile/builtin/main.go @@ -28,14 +28,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" cfg "sigs.k8s.io/controller-runtime/pkg/config" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" "sigs.k8s.io/controller-runtime/pkg/manager/signals" ) var scheme = runtime.NewScheme() func init() { - log.SetLogger(zap.New()) + log.SetLogger(bootstrap.New()) clientgoscheme.AddToScheme(scheme) } diff --git a/examples/configfile/custom/main.go b/examples/configfile/custom/main.go index e0fc95e337..a4a011a14c 100644 --- a/examples/configfile/custom/main.go +++ b/examples/configfile/custom/main.go @@ -29,14 +29,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" cfg "sigs.k8s.io/controller-runtime/pkg/config" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" "sigs.k8s.io/controller-runtime/pkg/manager/signals" ) var scheme = runtime.NewScheme() func init() { - log.SetLogger(zap.New()) + log.SetLogger(bootstrap.New()) clientgoscheme.AddToScheme(scheme) v1alpha1.AddToScheme(scheme) } diff --git a/examples/crd/main.go b/examples/crd/main.go index 1f6cd5fac2..bdef1ff287 100644 --- a/examples/crd/main.go +++ b/examples/crd/main.go @@ -30,7 +30,7 @@ import ( api "sigs.k8s.io/controller-runtime/examples/crd/pkg" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" ) var ( @@ -102,7 +102,7 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } func main() { - ctrl.SetLogger(zap.New()) + ctrl.SetLogger(bootstrap.New()) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{}) if err != nil { diff --git a/examples/scratch-env/main.go b/examples/scratch-env/main.go index 13b8e03feb..b2fc8a2669 100644 --- a/examples/scratch-env/main.go +++ b/examples/scratch-env/main.go @@ -24,6 +24,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" "sigs.k8s.io/controller-runtime/pkg/log/zap" ) @@ -44,7 +45,7 @@ func runMain() int { flag.CommandLine.AddGoFlagSet(&goFlagSet) } flag.Parse() - ctrl.SetLogger(zap.New(zap.UseFlagOptions(loggerOpts))) + ctrl.SetLogger(bootstrap.New(zap.UseFlagOptions(loggerOpts))) log := ctrl.Log.WithName("main") diff --git a/examples/tokenreview/main.go b/examples/tokenreview/main.go index d018956f96..bb1cb5a982 100644 --- a/examples/tokenreview/main.go +++ b/examples/tokenreview/main.go @@ -22,14 +22,14 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/webhook/authentication" ) func init() { - log.SetLogger(zap.New()) + log.SetLogger(bootstrap.New()) } func main() { diff --git a/pkg/log/bootstrap/doc.go b/pkg/log/bootstrap/doc.go new file mode 100644 index 0000000000..2fafec144b --- /dev/null +++ b/pkg/log/bootstrap/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package bootstrap is used to bootstrap the logger with both customized zap and logr. +package bootstrap diff --git a/pkg/log/bootstrap/log.go b/pkg/log/bootstrap/log.go new file mode 100644 index 0000000000..3a362a277d --- /dev/null +++ b/pkg/log/bootstrap/log.go @@ -0,0 +1,37 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package bootstrap + +import ( + gologr "github.com/go-logr/logr" + gozapr "github.com/go-logr/zapr" + "sigs.k8s.io/controller-runtime/pkg/log/logr" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +// New returns a brand new Logger configured with Opts. It +// uses logr.NewKubeAwareLogSink which adds Type information and +// Namespace/Name to the log. +func New(opts ...zap.Opts) gologr.Logger { + zapLogger := gozapr.NewLogger(zap.NewRaw(opts...)) + + o := &zap.Options{} + for _, opt := range opts { + opt(o) + } + return logr.NewKubeAwareLogger(zapLogger, o.Development) +} diff --git a/pkg/log/logr/kube_aware_logger_sink.go b/pkg/log/logr/kube_aware_logger_sink.go index 908a9b20b1..b88df38d26 100644 --- a/pkg/log/logr/kube_aware_logger_sink.go +++ b/pkg/log/logr/kube_aware_logger_sink.go @@ -23,27 +23,41 @@ import ( "k8s.io/apimachinery/pkg/types" ) +var _ logr.LogSink = (*KubeAwareLogSink)(nil) + +// KubeAwareLogSink is a Kubernetes-aware logr.LogSink. +// zapcore.ObjectMarshaler would be bypassed when using zapr and WithValues. +// It would use a wrapper implements logr.Marshaler instead of using origin Kubernetes objects. type KubeAwareLogSink struct { sink logr.LogSink kubeAwareEnabled *atomic.Bool } +// NewKubeAwareLogger return the wrapper with existed logr.Logger. +// logger is the backend logger. +// kubeAwareEnabled is the flag to enable kube aware logging. func NewKubeAwareLogger(logger logr.Logger, kubeAwareEnabled bool) logr.Logger { return logr.New(NewKubeAwareLogSink(logger.GetSink(), kubeAwareEnabled)) } +// NewKubeAwareLogSink return the wrapper with existed logr.LogSink. +// sink is the backend logr.LogSink. +// kubeAwareEnabled is the flag to enable kube aware logging. func NewKubeAwareLogSink(logSink logr.LogSink, kubeAwareEnabled bool) *KubeAwareLogSink { return &KubeAwareLogSink{sink: logSink, kubeAwareEnabled: atomic.NewBool(kubeAwareEnabled)} } +// Init implements logr.LogSink. func (k *KubeAwareLogSink) Init(info logr.RuntimeInfo) { k.sink.Init(info) } +// Enabled implements logr.LogSink. func (k *KubeAwareLogSink) Enabled(level int) bool { return k.sink.Enabled(level) } +// Info implements logr.LogSink. func (k *KubeAwareLogSink) Info(level int, msg string, keysAndValues ...interface{}) { if !k.KubeAwareEnabled() { k.sink.Info(level, msg, keysAndValues...) @@ -53,6 +67,7 @@ func (k *KubeAwareLogSink) Info(level int, msg string, keysAndValues ...interfac k.sink.Info(level, msg, k.wrapKeyAndValues(keysAndValues)...) } +// Error implements logr.LogSink. func (k *KubeAwareLogSink) Error(err error, msg string, keysAndValues ...interface{}) { if !k.KubeAwareEnabled() { k.sink.Error(err, msg, keysAndValues...) @@ -61,27 +76,7 @@ func (k *KubeAwareLogSink) Error(err error, msg string, keysAndValues ...interfa k.sink.Error(err, msg, k.wrapKeyAndValues(keysAndValues)...) } -func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []interface{} { - result := make([]interface{}, len(keysAndValues)) - for i, item := range keysAndValues { - if i%2 == 0 { - // item is key, no need to resolve - result[i] = item - continue - } - - switch val := item.(type) { - case runtime.Object: - result[i] = &kubeObjectWrapper{obj: val} - case types.NamespacedName: - result[i] = &namespacedNameWrapper{NamespacedName: val} - default: - result[i] = item - } - } - return result -} - +// WithValues implements logr.LogSink. func (k *KubeAwareLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { return &KubeAwareLogSink{ kubeAwareEnabled: k.kubeAwareEnabled, @@ -89,6 +84,7 @@ func (k *KubeAwareLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink } } +// WithName implements logr.LogSink. func (k *KubeAwareLogSink) WithName(name string) logr.LogSink { return &KubeAwareLogSink{ kubeAwareEnabled: k.kubeAwareEnabled, @@ -96,10 +92,34 @@ func (k *KubeAwareLogSink) WithName(name string) logr.LogSink { } } +// KubeAwareEnabled return kube aware logging is enabled or not. func (k *KubeAwareLogSink) KubeAwareEnabled() bool { return k.kubeAwareEnabled.Load() } +// SetKubeAwareEnabled could update the kube aware logging flag. func (k *KubeAwareLogSink) SetKubeAwareEnabled(enabled bool) { k.kubeAwareEnabled.Store(enabled) } + +// wrapKeyAndValues would replace the kubernetes objects with wrappers. +func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []interface{} { + result := make([]interface{}, len(keysAndValues)) + for i, item := range keysAndValues { + if i%2 == 0 { + // item is key, no need to resolve + result[i] = item + continue + } + + switch val := item.(type) { + case runtime.Object: + result[i] = &kubeObjectWrapper{obj: val} + case types.NamespacedName: + result[i] = &namespacedNameWrapper{NamespacedName: val} + default: + result[i] = item + } + } + return result +} diff --git a/pkg/log/logr/kube_object_wrapper.go b/pkg/log/logr/kube_object_wrapper.go index ee964fef99..589078589c 100644 --- a/pkg/log/logr/kube_object_wrapper.go +++ b/pkg/log/logr/kube_object_wrapper.go @@ -17,11 +17,15 @@ limitations under the License. package logr import ( + "reflect" + + "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" - "reflect" ) +var _ logr.Marshaler = (*kubeObjectWrapper)(nil) + type kubeObjectWrapper struct { obj runtime.Object } diff --git a/pkg/log/logr/logr_test.go b/pkg/log/logr/logr_test.go index 270d715622..66a4d07267 100644 --- a/pkg/log/logr/logr_test.go +++ b/pkg/log/logr/logr_test.go @@ -18,7 +18,9 @@ package logr import ( "bytes" + "encoding/json" + "github.com/go-logr/logr" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -79,7 +81,7 @@ var _ = Describe("Logr logSink setup", func() { It("should log a standard non-namespaced Kubernetes object name", func() { node := &corev1.Node{} - node.Name = "some-node" + node.Name = "some-node-1" logger.Info("here's a kubernetes object", "thing", node) outRaw := logOut.Bytes() @@ -93,7 +95,7 @@ var _ = Describe("Logr logSink setup", func() { It("should log a standard Kubernetes object's kind, if set", func() { node := &corev1.Node{} - node.Name = "some-node" + node.Name = "some-node-2" node.APIVersion = "v1" node.Kind = "Node" logger.Info("here's a kubernetes object", "thing", node) @@ -110,7 +112,7 @@ var _ = Describe("Logr logSink setup", func() { }) It("should log a standard non-namespaced NamespacedName name", func() { - name := types.NamespacedName{Name: "some-node"} + name := types.NamespacedName{Name: "some-node-3"} logger.Info("here's a kubernetes object", "thing", name) outRaw := logOut.Bytes() diff --git a/pkg/log/logr/namespaced_name_wrapper.go b/pkg/log/logr/namespaced_name_wrapper.go index 89c12cd512..171413fd4d 100644 --- a/pkg/log/logr/namespaced_name_wrapper.go +++ b/pkg/log/logr/namespaced_name_wrapper.go @@ -16,7 +16,12 @@ limitations under the License. package logr -import "k8s.io/apimachinery/pkg/types" +import ( + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/types" +) + +var _ logr.Marshaler = (*namespacedNameWrapper)(nil) type namespacedNameWrapper struct { types.NamespacedName diff --git a/pkg/log/zap/zap.go b/pkg/log/zap/zap.go index 71cdc4ae01..093e1c1127 100644 --- a/pkg/log/zap/zap.go +++ b/pkg/log/zap/zap.go @@ -39,6 +39,7 @@ type NewEncoderFunc func(...EncoderConfigOption) zapcore.Encoder // New returns a brand new Logger configured with Opts. It // uses KubeAwareEncoder which adds Type information and // Namespace/Name to the log. +// Deprecated: use bootstrap.New as instead. func New(opts ...Opts) logr.Logger { return zapr.NewLogger(NewRaw(opts...)) } diff --git a/pkg/log/zap/zap_test.go b/pkg/log/zap/zap_test.go index 06fbff4ce0..819236adbd 100644 --- a/pkg/log/zap/zap_test.go +++ b/pkg/log/zap/zap_test.go @@ -178,7 +178,7 @@ var _ = Describe("Zap logger setup", func() { It("should log a standard non-namespaced Kubernetes object name", func() { node := &corev1.Node{} - node.Name = "some-node" + node.Name = "some-node-1" logger.Info("here's a kubernetes object", "thing", node) outRaw := logOut.Bytes() @@ -192,7 +192,7 @@ var _ = Describe("Zap logger setup", func() { It("should log a standard Kubernetes object's kind, if set", func() { node := &corev1.Node{} - node.Name = "some-node" + node.Name = "some-node-2" node.APIVersion = "v1" node.Kind = "Node" logger.Info("here's a kubernetes object", "thing", node) @@ -209,7 +209,7 @@ var _ = Describe("Zap logger setup", func() { }) It("should log a standard non-namespaced NamespacedName name", func() { - name := types.NamespacedName{Name: "some-node"} + name := types.NamespacedName{Name: "some-node-3"} logger.Info("here's a kubernetes object", "thing", name) outRaw := logOut.Bytes() From e4411c46b06b63ddf38e0694ca1b07f2e7e69df7 Mon Sep 17 00:00:00 2001 From: STRRL Date: Sun, 17 Jul 2022 10:29:22 +0800 Subject: [PATCH 6/8] chore: still using zap.New as the default logger bootstrapper Signed-off-by: STRRL --- examples/builtins/main.go | 4 +- examples/configfile/builtin/main.go | 4 +- examples/configfile/custom/main.go | 4 +- examples/crd/main.go | 4 +- examples/scratch-env/main.go | 3 +- examples/tokenreview/main.go | 4 +- go.mod | 2 +- pkg/log/bootstrap/doc.go | 18 -- pkg/log/bootstrap/log.go | 37 --- pkg/log/logr/doc.go | 19 -- pkg/log/logr/logr_suite_test.go | 31 --- pkg/log/logr/logr_test.go | 226 ------------------ .../{logr => zap}/kube_aware_logger_sink.go | 2 +- pkg/log/{logr => zap}/kube_object_wrapper.go | 8 +- .../{logr => zap}/namespaced_name_wrapper.go | 8 +- pkg/log/zap/zap.go | 19 +- pkg/log/zap/zap_test.go | 29 +-- 17 files changed, 38 insertions(+), 384 deletions(-) delete mode 100644 pkg/log/bootstrap/doc.go delete mode 100644 pkg/log/bootstrap/log.go delete mode 100644 pkg/log/logr/doc.go delete mode 100644 pkg/log/logr/logr_suite_test.go delete mode 100644 pkg/log/logr/logr_test.go rename pkg/log/{logr => zap}/kube_aware_logger_sink.go (99%) rename pkg/log/{logr => zap}/kube_object_wrapper.go (87%) rename pkg/log/{logr => zap}/namespaced_name_wrapper.go (81%) diff --git a/examples/builtins/main.go b/examples/builtins/main.go index 44ef212575..ff1f0dfa3b 100644 --- a/examples/builtins/main.go +++ b/examples/builtins/main.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" + "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/source" @@ -34,7 +34,7 @@ import ( ) func init() { - log.SetLogger(bootstrap.New()) + log.SetLogger(zap.New()) } func main() { diff --git a/examples/configfile/builtin/main.go b/examples/configfile/builtin/main.go index 793755a1f2..abd6180d19 100644 --- a/examples/configfile/builtin/main.go +++ b/examples/configfile/builtin/main.go @@ -28,14 +28,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" cfg "sigs.k8s.io/controller-runtime/pkg/config" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" + "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager/signals" ) var scheme = runtime.NewScheme() func init() { - log.SetLogger(bootstrap.New()) + log.SetLogger(zap.New()) clientgoscheme.AddToScheme(scheme) } diff --git a/examples/configfile/custom/main.go b/examples/configfile/custom/main.go index a4a011a14c..e0fc95e337 100644 --- a/examples/configfile/custom/main.go +++ b/examples/configfile/custom/main.go @@ -29,14 +29,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" cfg "sigs.k8s.io/controller-runtime/pkg/config" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" + "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager/signals" ) var scheme = runtime.NewScheme() func init() { - log.SetLogger(bootstrap.New()) + log.SetLogger(zap.New()) clientgoscheme.AddToScheme(scheme) v1alpha1.AddToScheme(scheme) } diff --git a/examples/crd/main.go b/examples/crd/main.go index bdef1ff287..1f6cd5fac2 100644 --- a/examples/crd/main.go +++ b/examples/crd/main.go @@ -30,7 +30,7 @@ import ( api "sigs.k8s.io/controller-runtime/examples/crd/pkg" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" + "sigs.k8s.io/controller-runtime/pkg/log/zap" ) var ( @@ -102,7 +102,7 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } func main() { - ctrl.SetLogger(bootstrap.New()) + ctrl.SetLogger(zap.New()) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{}) if err != nil { diff --git a/examples/scratch-env/main.go b/examples/scratch-env/main.go index b2fc8a2669..13b8e03feb 100644 --- a/examples/scratch-env/main.go +++ b/examples/scratch-env/main.go @@ -24,7 +24,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" "sigs.k8s.io/controller-runtime/pkg/log/zap" ) @@ -45,7 +44,7 @@ func runMain() int { flag.CommandLine.AddGoFlagSet(&goFlagSet) } flag.Parse() - ctrl.SetLogger(bootstrap.New(zap.UseFlagOptions(loggerOpts))) + ctrl.SetLogger(zap.New(zap.UseFlagOptions(loggerOpts))) log := ctrl.Log.WithName("main") diff --git a/examples/tokenreview/main.go b/examples/tokenreview/main.go index bb1cb5a982..d018956f96 100644 --- a/examples/tokenreview/main.go +++ b/examples/tokenreview/main.go @@ -22,14 +22,14 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/bootstrap" + "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/manager/signals" "sigs.k8s.io/controller-runtime/pkg/webhook/authentication" ) func init() { - log.SetLogger(bootstrap.New()) + log.SetLogger(zap.New()) } func main() { diff --git a/go.mod b/go.mod index 771f75574b..4f27a9d1cd 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/onsi/gomega v1.19.0 github.com/prometheus/client_golang v1.12.2 github.com/prometheus/client_model v0.2.0 + go.uber.org/atomic v1.7.0 go.uber.org/goleak v1.1.12 go.uber.org/zap v1.21.0 golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c @@ -58,7 +59,6 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect diff --git a/pkg/log/bootstrap/doc.go b/pkg/log/bootstrap/doc.go deleted file mode 100644 index 2fafec144b..0000000000 --- a/pkg/log/bootstrap/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2022 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package bootstrap is used to bootstrap the logger with both customized zap and logr. -package bootstrap diff --git a/pkg/log/bootstrap/log.go b/pkg/log/bootstrap/log.go deleted file mode 100644 index 3a362a277d..0000000000 --- a/pkg/log/bootstrap/log.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2022 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package bootstrap - -import ( - gologr "github.com/go-logr/logr" - gozapr "github.com/go-logr/zapr" - "sigs.k8s.io/controller-runtime/pkg/log/logr" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -// New returns a brand new Logger configured with Opts. It -// uses logr.NewKubeAwareLogSink which adds Type information and -// Namespace/Name to the log. -func New(opts ...zap.Opts) gologr.Logger { - zapLogger := gozapr.NewLogger(zap.NewRaw(opts...)) - - o := &zap.Options{} - for _, opt := range opts { - opt(o) - } - return logr.NewKubeAwareLogger(zapLogger, o.Development) -} diff --git a/pkg/log/logr/doc.go b/pkg/log/logr/doc.go deleted file mode 100644 index 6f955300bb..0000000000 --- a/pkg/log/logr/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2022 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package logr introduces an implementation of logr.LogSink, which could -// encode Kubernetes Objects into Type information and Namespace/Name. -package logr diff --git a/pkg/log/logr/logr_suite_test.go b/pkg/log/logr/logr_suite_test.go deleted file mode 100644 index 64bf783069..0000000000 --- a/pkg/log/logr/logr_suite_test.go +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2022 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package logr - -import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" -) - -func TestSource(t *testing.T) { - RegisterFailHandler(Fail) - suiteName := "Logr Log Suite" - RunSpecsWithDefaultAndCustomReporters(t, suiteName, []Reporter{printer.NewlineReporter{}, printer.NewProwReporter(suiteName)}) -} diff --git a/pkg/log/logr/logr_test.go b/pkg/log/logr/logr_test.go deleted file mode 100644 index 66a4d07267..0000000000 --- a/pkg/log/logr/logr_test.go +++ /dev/null @@ -1,226 +0,0 @@ -/* -Copyright 2022 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package logr - -import ( - "bytes" - - "encoding/json" - - "github.com/go-logr/logr" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -// testStringer is a fmt.Stringer. -type testStringer struct{} - -func (testStringer) String() string { - return "value" -} - -var _ = Describe("Logr logSink setup", func() { - - Context("when logging kubernetes objects", func() { - var logOut *bytes.Buffer - var zaplogger logr.Logger - var logger logr.Logger - - Context("with logger created using zap.New", func() { - BeforeEach(func() { - logOut = new(bytes.Buffer) - By("setting up the logger") - // use production settings (false) to get just json output - zaplogger = zap.New(zap.WriteTo(logOut), zap.UseDevMode(false)) - logger = NewKubeAwareLogger(zaplogger, true) - - }) - - It("should log a standard namespaced Kubernetes object name and namespace", func() { - pod := &corev1.Pod{} - pod.Name = "some-pod" - pod.Namespace = "some-ns" - logger.Info("here's a kubernetes object", "thing", pod) - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": pod.Name, - "namespace": pod.Namespace, - })) - }) - - It("should work fine with normal stringers", func() { - logger.Info("here's a non-kubernetes stringer", "thing", testStringer{}) - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", "value")) - }) - - It("should log a standard non-namespaced Kubernetes object name", func() { - node := &corev1.Node{} - node.Name = "some-node-1" - logger.Info("here's a kubernetes object", "thing", node) - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": node.Name, - })) - }) - - It("should log a standard Kubernetes object's kind, if set", func() { - node := &corev1.Node{} - node.Name = "some-node-2" - node.APIVersion = "v1" - node.Kind = "Node" - logger.Info("here's a kubernetes object", "thing", node) - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": node.Name, - "apiVersion": "v1", - "kind": "Node", - })) - }) - - It("should log a standard non-namespaced NamespacedName name", func() { - name := types.NamespacedName{Name: "some-node-3"} - logger.Info("here's a kubernetes object", "thing", name) - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": name.Name, - })) - }) - - It("should log an unstructured Kubernetes object", func() { - pod := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "some-pod", - "namespace": "some-ns", - }, - }, - } - logger.Info("here's a kubernetes object", "thing", pod) - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": "some-pod", - "namespace": "some-ns", - })) - }) - - It("should log a standard namespaced NamespacedName name and namespace", func() { - name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"} - logger.Info("here's a kubernetes object", "thing", name) - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": name.Name, - "namespace": name.Namespace, - })) - }) - - It("should not panic with nil obj", func() { - var pod *corev1.Pod - logger.Info("here's a kubernetes object", "thing", pod) - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - Expect(res).To(HaveKey("thing")) - Expect(res["things"]).To(BeNil()) - }) - - It("should log a standard namespaced when using logrLogger.WithValues", func() { - name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"} - logger.WithValues("thing", name).Info("here's a kubernetes object") - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": name.Name, - "namespace": name.Namespace, - })) - }) - - It("should log a standard Kubernetes objects when using logrLogger.WithValues", func() { - node := &corev1.Node{} - node.Name = "some-node" - node.APIVersion = "v1" - node.Kind = "Node" - logger.WithValues("thing", node).Info("here's a kubernetes object") - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": node.Name, - "apiVersion": "v1", - "kind": "Node", - })) - }) - - It("should log a standard unstructured Kubernetes object when using logrLogger.WithValues", func() { - pod := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "some-pod", - "namespace": "some-ns", - }, - }, - } - logger.WithValues("thing", pod).Info("here's a kubernetes object") - - outRaw := logOut.Bytes() - res := map[string]interface{}{} - Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - - Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ - "name": "some-pod", - "namespace": "some-ns", - })) - }) - }) - }) -}) diff --git a/pkg/log/logr/kube_aware_logger_sink.go b/pkg/log/zap/kube_aware_logger_sink.go similarity index 99% rename from pkg/log/logr/kube_aware_logger_sink.go rename to pkg/log/zap/kube_aware_logger_sink.go index b88df38d26..e4bdb14f79 100644 --- a/pkg/log/logr/kube_aware_logger_sink.go +++ b/pkg/log/zap/kube_aware_logger_sink.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package logr +package zap import ( "github.com/go-logr/logr" diff --git a/pkg/log/logr/kube_object_wrapper.go b/pkg/log/zap/kube_object_wrapper.go similarity index 87% rename from pkg/log/logr/kube_object_wrapper.go rename to pkg/log/zap/kube_object_wrapper.go index 589078589c..f6f317719e 100644 --- a/pkg/log/logr/kube_object_wrapper.go +++ b/pkg/log/zap/kube_object_wrapper.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package logr +package zap import ( "reflect" @@ -24,13 +24,13 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -var _ logr.Marshaler = (*kubeObjectWrapper)(nil) +var _ logr.Marshaler = (*logrLoggerKubeObjectWrapper)(nil) -type kubeObjectWrapper struct { +type logrLoggerKubeObjectWrapper struct { obj runtime.Object } -func (w *kubeObjectWrapper) MarshalLog() interface{} { +func (w *logrLoggerKubeObjectWrapper) MarshalLog() interface{} { result := make(map[string]string) if reflect.ValueOf(w.obj).IsNil() { diff --git a/pkg/log/logr/namespaced_name_wrapper.go b/pkg/log/zap/namespaced_name_wrapper.go similarity index 81% rename from pkg/log/logr/namespaced_name_wrapper.go rename to pkg/log/zap/namespaced_name_wrapper.go index 171413fd4d..3742bf9e2b 100644 --- a/pkg/log/logr/namespaced_name_wrapper.go +++ b/pkg/log/zap/namespaced_name_wrapper.go @@ -14,20 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -package logr +package zap import ( "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/types" ) -var _ logr.Marshaler = (*namespacedNameWrapper)(nil) +var _ logr.Marshaler = (*logrLoggerNamespacedNameWrapper)(nil) -type namespacedNameWrapper struct { +type logrLoggerNamespacedNameWrapper struct { types.NamespacedName } -func (w *namespacedNameWrapper) MarshalLog() interface{} { +func (w *logrLoggerNamespacedNameWrapper) MarshalLog() interface{} { result := make(map[string]string) if w.Namespace != "" { result["namespace"] = w.Namespace diff --git a/pkg/log/zap/zap.go b/pkg/log/zap/zap.go index 093e1c1127..db46ab7b1b 100644 --- a/pkg/log/zap/zap.go +++ b/pkg/log/zap/zap.go @@ -37,11 +37,11 @@ type EncoderConfigOption func(*zapcore.EncoderConfig) type NewEncoderFunc func(...EncoderConfigOption) zapcore.Encoder // New returns a brand new Logger configured with Opts. It -// uses KubeAwareEncoder which adds Type information and -// Namespace/Name to the log. -// Deprecated: use bootstrap.New as instead. +// uses KubeAwareLogger/KubeAwareEncoder which adds Type +// information and Namespace/Name to the log. func New(opts ...Opts) logr.Logger { - return zapr.NewLogger(NewRaw(opts...)) + zaprLogger := zapr.NewLogger(NewRaw(opts...)) + return NewKubeAwareLogger(zaprLogger, true) } // Opts allows to manipulate Options. @@ -171,11 +171,6 @@ type Options struct { // TimeEncoder specifies the encoder for the timestamps in log messages. // Defaults to EpochTimeEncoder as this is the default in Zap currently. TimeEncoder zapcore.TimeEncoder - // UseKubeAwareEncoder configures the logger to use the KubeAwareEncoder for encoding kubernetes - // object as Type information and Namespace/Name. - // Note: KubeAwareEncoder could NOT resolve the object passed by logger.WithValues(), see - // https://github.com/kubernetes-sigs/controller-runtime/issues/1290 - UseKubeAwareEncoder bool } // addDefaults adds defaults to the Options. @@ -251,11 +246,7 @@ func NewRaw(opts ...Opts) *zap.Logger { sink := zapcore.AddSync(o.DestWriter) o.ZapOpts = append(o.ZapOpts, zap.AddCallerSkip(1), zap.ErrorOutput(sink)) - encoder := o.Encoder - if o.UseKubeAwareEncoder { - encoder = &KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development} - } - log := zap.New(zapcore.NewCore(encoder, sink, o.Level)) + log := zap.New(zapcore.NewCore(&KubeAwareEncoder{Encoder: o.Encoder, Verbose: o.Development}, sink, o.Level)) log = log.WithOptions(o.ZapOpts...) return log } diff --git a/pkg/log/zap/zap_test.go b/pkg/log/zap/zap_test.go index 819236adbd..aa67de8b20 100644 --- a/pkg/log/zap/zap_test.go +++ b/pkg/log/zap/zap_test.go @@ -145,6 +145,8 @@ var _ = Describe("Zap options setup", func() { }) }) +const kindNode = "Node" + var _ = Describe("Zap logger setup", func() { Context("when logging kubernetes objects", func() { var logOut *bytes.Buffer @@ -194,7 +196,7 @@ var _ = Describe("Zap logger setup", func() { node := &corev1.Node{} node.Name = "some-node-2" node.APIVersion = "v1" - node.Kind = "Node" + node.Kind = kindNode logger.Info("here's a kubernetes object", "thing", node) outRaw := logOut.Bytes() @@ -204,7 +206,7 @@ var _ = Describe("Zap logger setup", func() { Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ "name": node.Name, "apiVersion": "v1", - "kind": "Node", + "kind": kindNode, })) }) @@ -263,9 +265,7 @@ var _ = Describe("Zap logger setup", func() { outRaw := logOut.Bytes() Expect(string(outRaw)).Should(ContainSubstring("got nil for runtime.Object")) }) - - // see https://github.com/kubernetes-sigs/controller-runtime/issues/1290 - It("should log NamespacedName as origin stringer when using logrLogger.WithValues", func() { + It("should log a standard namespaced when using logrLogger.WithValues", func() { name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"} logger.WithValues("thing", name).Info("here's a kubernetes object") @@ -273,35 +273,31 @@ var _ = Describe("Zap logger setup", func() { res := map[string]interface{}{} Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - Expect(res).NotTo(HaveKeyWithValue("thing", map[string]interface{}{ + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ "name": name.Name, "namespace": name.Namespace, })) - Expect(res).To(HaveKeyWithValue("thing", "some-ns/some-pod")) }) - // see https://github.com/kubernetes-sigs/controller-runtime/issues/1290 - It("should log Kubernetes objects as origin stringer when using logrLogger.WithValues", func() { + It("should log a standard Kubernetes objects when using logrLogger.WithValues", func() { node := &corev1.Node{} node.Name = "some-node" node.APIVersion = "v1" - node.Kind = "Node" + node.Kind = kindNode logger.WithValues("thing", node).Info("here's a kubernetes object") outRaw := logOut.Bytes() res := map[string]interface{}{} Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - Expect(res).NotTo(HaveKeyWithValue("thing", map[string]interface{}{ + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ "name": node.Name, "apiVersion": "v1", - "kind": "Node", + "kind": kindNode, })) - Expect(res).To(HaveKeyWithValue("thing", "&Node{ObjectMeta:{some-node 0 0001-01-01 00:00:00 +0000 UTC map[] map[] [] [] []},Spec:NodeSpec{PodCIDR:,DoNotUseExternalID:,ProviderID:,Unschedulable:false,Taints:[]Taint{},ConfigSource:nil,PodCIDRs:[],},Status:NodeStatus{Capacity:ResourceList{},Allocatable:ResourceList{},Phase:,Conditions:[]NodeCondition{},Addresses:[]NodeAddress{},DaemonEndpoints:NodeDaemonEndpoints{KubeletEndpoint:DaemonEndpoint{Port:0,},},NodeInfo:NodeSystemInfo{MachineID:,SystemUUID:,BootID:,KernelVersion:,OSImage:,ContainerRuntimeVersion:,KubeletVersion:,KubeProxyVersion:,OperatingSystem:,Architecture:,},Images:[]ContainerImage{},VolumesInUse:[],VolumesAttached:[]AttachedVolume{},Config:nil,},}")) }) - // see https://github.com/kubernetes-sigs/controller-runtime/issues/1290 - It("should log an unstructured Kubernetes object as origin stringer when using logrLogger.WithValues", func() { + It("should log a standard unstructured Kubernetes object when using logrLogger.WithValues", func() { pod := &unstructured.Unstructured{ Object: map[string]interface{}{ "metadata": map[string]interface{}{ @@ -316,11 +312,10 @@ var _ = Describe("Zap logger setup", func() { res := map[string]interface{}{} Expect(json.Unmarshal(outRaw, &res)).To(Succeed()) - Expect(res).NotTo(HaveKeyWithValue("thing", map[string]interface{}{ + Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{ "name": "some-pod", "namespace": "some-ns", })) - Expect(res).To(HaveKeyWithValue("thing", pod.Object)) }) } From 705bd0ccb7afcca018d139da8e68628f1981d973 Mon Sep 17 00:00:00 2001 From: STRRL Date: Sun, 17 Jul 2022 11:40:47 +0800 Subject: [PATCH 7/8] fix: fix testcases Signed-off-by: STRRL --- ...ware_logger_sink.go => kube_aware_logr_logger_sink.go} | 8 ++++---- ...ject_wrapper.go => logr_logger_kube_object_wrapper.go} | 4 ++-- ..._wrapper.go => logr_logger_namespaced_name_wrapper.go} | 0 pkg/log/zap/zap.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename pkg/log/zap/{kube_aware_logger_sink.go => kube_aware_logr_logger_sink.go} (92%) rename pkg/log/zap/{kube_object_wrapper.go => logr_logger_kube_object_wrapper.go} (93%) rename pkg/log/zap/{namespaced_name_wrapper.go => logr_logger_namespaced_name_wrapper.go} (100%) diff --git a/pkg/log/zap/kube_aware_logger_sink.go b/pkg/log/zap/kube_aware_logr_logger_sink.go similarity index 92% rename from pkg/log/zap/kube_aware_logger_sink.go rename to pkg/log/zap/kube_aware_logr_logger_sink.go index e4bdb14f79..df5365c505 100644 --- a/pkg/log/zap/kube_aware_logger_sink.go +++ b/pkg/log/zap/kube_aware_logr_logger_sink.go @@ -33,10 +33,10 @@ type KubeAwareLogSink struct { kubeAwareEnabled *atomic.Bool } -// NewKubeAwareLogger return the wrapper with existed logr.Logger. +// NewKubeAwareLogrLogger return the wrapper with existed logr.Logger. // logger is the backend logger. // kubeAwareEnabled is the flag to enable kube aware logging. -func NewKubeAwareLogger(logger logr.Logger, kubeAwareEnabled bool) logr.Logger { +func NewKubeAwareLogrLogger(logger logr.Logger, kubeAwareEnabled bool) logr.Logger { return logr.New(NewKubeAwareLogSink(logger.GetSink(), kubeAwareEnabled)) } @@ -114,9 +114,9 @@ func (k *KubeAwareLogSink) wrapKeyAndValues(keysAndValues []interface{}) []inter switch val := item.(type) { case runtime.Object: - result[i] = &kubeObjectWrapper{obj: val} + result[i] = &logrLoggerKubeObjectWrapper{obj: val} case types.NamespacedName: - result[i] = &namespacedNameWrapper{NamespacedName: val} + result[i] = &logrLoggerNamespacedNameWrapper{NamespacedName: val} default: result[i] = item } diff --git a/pkg/log/zap/kube_object_wrapper.go b/pkg/log/zap/logr_logger_kube_object_wrapper.go similarity index 93% rename from pkg/log/zap/kube_object_wrapper.go rename to pkg/log/zap/logr_logger_kube_object_wrapper.go index f6f317719e..a7cdbd9ed3 100644 --- a/pkg/log/zap/kube_object_wrapper.go +++ b/pkg/log/zap/logr_logger_kube_object_wrapper.go @@ -34,8 +34,8 @@ func (w *logrLoggerKubeObjectWrapper) MarshalLog() interface{} { result := make(map[string]string) if reflect.ValueOf(w.obj).IsNil() { - // best effort ,noop - return nil + // keep same behavior with kubeObjectWrapper.MarshalLogObject + return "got nil for runtime.Object" } if gvk := w.obj.GetObjectKind().GroupVersionKind(); gvk.Version != "" { diff --git a/pkg/log/zap/namespaced_name_wrapper.go b/pkg/log/zap/logr_logger_namespaced_name_wrapper.go similarity index 100% rename from pkg/log/zap/namespaced_name_wrapper.go rename to pkg/log/zap/logr_logger_namespaced_name_wrapper.go diff --git a/pkg/log/zap/zap.go b/pkg/log/zap/zap.go index db46ab7b1b..730c703c4e 100644 --- a/pkg/log/zap/zap.go +++ b/pkg/log/zap/zap.go @@ -41,7 +41,7 @@ type NewEncoderFunc func(...EncoderConfigOption) zapcore.Encoder // information and Namespace/Name to the log. func New(opts ...Opts) logr.Logger { zaprLogger := zapr.NewLogger(NewRaw(opts...)) - return NewKubeAwareLogger(zaprLogger, true) + return NewKubeAwareLogrLogger(zaprLogger, true) } // Opts allows to manipulate Options. From 2b181798b5445b6bcf4acf474978699c0e10f865 Mon Sep 17 00:00:00 2001 From: STRRL Date: Tue, 26 Nov 2024 06:06:35 -0800 Subject: [PATCH 8/8] chore: `make modules` for sync deps Signed-off-by: STRRL --- examples/scratch-env/go.mod | 1 + examples/scratch-env/go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/examples/scratch-env/go.mod b/examples/scratch-env/go.mod index 010adc9379..72ccf80ab6 100644 --- a/examples/scratch-env/go.mod +++ b/examples/scratch-env/go.mod @@ -39,6 +39,7 @@ require ( github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/x448/float16 v0.8.4 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect diff --git a/examples/scratch-env/go.sum b/examples/scratch-env/go.sum index b5246d60a2..5b2239ea14 100644 --- a/examples/scratch-env/go.sum +++ b/examples/scratch-env/go.sum @@ -103,6 +103,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=