1 /* 2 Copyright 2023 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 klog 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "strings" 23 24 "github.com/go-logr/logr" 25 ) 26 27 // Format wraps a value of an arbitrary type and implement fmt.Stringer and 28 // logr.Marshaler for them. Stringer returns pretty-printed JSON. MarshalLog 29 // returns the original value with a type that has no special methods, in 30 // particular no MarshalLog or MarshalJSON. 31 // 32 // Wrapping values like that is useful when the value has a broken 33 // implementation of these special functions (for example, a type which 34 // inherits String from TypeMeta, but then doesn't re-implement String) or the 35 // implementation produces output that is less readable or unstructured (for 36 // example, the generated String functions for Kubernetes API types). 37 func Format(obj interface{}) interface{} { 38 return formatAny{Object: obj} 39 } 40 41 type formatAny struct { 42 Object interface{} 43 } 44 45 func (f formatAny) String() string { 46 var buffer strings.Builder 47 encoder := json.NewEncoder(&buffer) 48 encoder.SetIndent("", " ") 49 if err := encoder.Encode(&f.Object); err != nil { 50 return fmt.Sprintf("error marshaling %T to JSON: %v", f, err) 51 } 52 return buffer.String() 53 } 54 55 func (f formatAny) MarshalLog() interface{} { 56 // Returning a pointer to a pointer ensures that zapr doesn't find a 57 // fmt.Stringer or logr.Marshaler when it checks the type of the 58 // value. It then falls back to reflection, which dumps the value being 59 // pointed to (JSON doesn't have pointers). 60 ptr := &f.Object 61 return &ptr 62 } 63 64 var _ fmt.Stringer = formatAny{} 65 var _ logr.Marshaler = formatAny{} 66