Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / sigs.k8s.io / controller-runtime / pkg / runtime / log / kube_helpers.go
1 /*
2 Copyright 2018 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 log contains utilities for fetching a new logger
18 // when one is not already available.
19 package log
20
21 import (
22         "fmt"
23
24         "go.uber.org/zap/buffer"
25         "go.uber.org/zap/zapcore"
26         "k8s.io/apimachinery/pkg/api/meta"
27         "k8s.io/apimachinery/pkg/runtime"
28         "k8s.io/apimachinery/pkg/types"
29 )
30
31 // KubeAwareEncoder is a Kubernetes-aware Zap Encoder.
32 // Instead of trying to force Kubernetes objects to implement
33 // ObjectMarshaller, we just implement a wrapper around a normal
34 // ObjectMarshaller that checks for Kubernetes objects.
35 type KubeAwareEncoder struct {
36         // Encoder is the zapcore.Encoder that this encoder delegates to
37         zapcore.Encoder
38
39         // Verbose controls whether or not the full object is printed.
40         // If false, only name, namespace, api version, and kind are printed.
41         // Otherwise, the full object is logged.
42         Verbose bool
43 }
44
45 // namespacedNameWrapper is a zapcore.ObjectMarshaler for Kubernetes NamespacedName
46 type namespacedNameWrapper struct {
47         types.NamespacedName
48 }
49
50 func (w namespacedNameWrapper) MarshalLogObject(enc zapcore.ObjectEncoder) error {
51         if w.Namespace != "" {
52                 enc.AddString("namespace", w.Namespace)
53         }
54
55         enc.AddString("name", w.Name)
56
57         return nil
58 }
59
60 // kubeObjectWrapper is a zapcore.ObjectMarshaler for Kubernetes objects.
61 type kubeObjectWrapper struct {
62         obj runtime.Object
63 }
64
65 // MarshalLogObject implements zapcore.ObjectMarshaler
66 func (w kubeObjectWrapper) MarshalLogObject(enc zapcore.ObjectEncoder) error {
67         // TODO(directxman12): log kind and apiversion if not set explicitly (common case)
68         // -- needs an a scheme to convert to the GVK.
69         gvk := w.obj.GetObjectKind().GroupVersionKind()
70         if gvk.Version != "" {
71                 enc.AddString("apiVersion", gvk.GroupVersion().String())
72                 enc.AddString("kind", gvk.Kind)
73         }
74
75         objMeta, err := meta.Accessor(w.obj)
76         if err != nil {
77                 return fmt.Errorf("got runtime.Object without object metadata: %v", w.obj)
78         }
79
80         ns := objMeta.GetNamespace()
81         if ns != "" {
82                 enc.AddString("namespace", ns)
83         }
84         enc.AddString("name", objMeta.GetName())
85
86         return nil
87 }
88
89 // NB(directxman12): can't just override AddReflected, since the encoder calls AddReflected on itself directly
90
91 // Clone implements zapcore.Encoder
92 func (k *KubeAwareEncoder) Clone() zapcore.Encoder {
93         return &KubeAwareEncoder{
94                 Encoder: k.Encoder.Clone(),
95         }
96 }
97
98 // EncodeEntry implements zapcore.Encoder
99 func (k *KubeAwareEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
100         if k.Verbose {
101                 // Kubernetes objects implement fmt.Stringer, so if we
102                 // want verbose output, just delegate to that.
103                 return k.Encoder.EncodeEntry(entry, fields)
104         }
105
106         for i, field := range fields {
107                 // intercept stringer fields that happen to be Kubernetes runtime.Object or
108                 // types.NamespacedName values (Kubernetes runtime.Objects commonly
109                 // implement String, apparently).
110                 if field.Type == zapcore.StringerType {
111                         switch val := field.Interface.(type) {
112                         case runtime.Object:
113                                 fields[i] = zapcore.Field{
114                                         Type:      zapcore.ObjectMarshalerType,
115                                         Key:       field.Key,
116                                         Interface: kubeObjectWrapper{obj: val},
117                                 }
118                         case types.NamespacedName:
119                                 fields[i] = zapcore.Field{
120                                         Type:      zapcore.ObjectMarshalerType,
121                                         Key:       field.Key,
122                                         Interface: namespacedNameWrapper{NamespacedName: val},
123                                 }
124                         }
125                 }
126         }
127
128         return k.Encoder.EncodeEntry(entry, fields)
129 }