format.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. /*
  2. Copyright 2023 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package klog
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "strings"
  18. "github.com/go-logr/logr"
  19. )
  20. // Format wraps a value of an arbitrary type and implement fmt.Stringer and
  21. // logr.Marshaler for them. Stringer returns pretty-printed JSON. MarshalLog
  22. // returns the original value with a type that has no special methods, in
  23. // particular no MarshalLog or MarshalJSON.
  24. //
  25. // Wrapping values like that is useful when the value has a broken
  26. // implementation of these special functions (for example, a type which
  27. // inherits String from TypeMeta, but then doesn't re-implement String) or the
  28. // implementation produces output that is less readable or unstructured (for
  29. // example, the generated String functions for Kubernetes API types).
  30. func Format(obj interface{}) interface{} {
  31. return formatAny{Object: obj}
  32. }
  33. type formatAny struct {
  34. Object interface{}
  35. }
  36. func (f formatAny) String() string {
  37. var buffer strings.Builder
  38. encoder := json.NewEncoder(&buffer)
  39. encoder.SetIndent("", " ")
  40. if err := encoder.Encode(&f.Object); err != nil {
  41. return fmt.Sprintf("error marshaling %T to JSON: %v", f, err)
  42. }
  43. return buffer.String()
  44. }
  45. func (f formatAny) MarshalLog() interface{} {
  46. // Returning a pointer to a pointer ensures that zapr doesn't find a
  47. // fmt.Stringer or logr.Marshaler when it checks the type of the
  48. // value. It then falls back to reflection, which dumps the value being
  49. // pointed to (JSON doesn't have pointers).
  50. ptr := &f.Object
  51. return &ptr
  52. }
  53. var _ fmt.Stringer = formatAny{}
  54. var _ logr.Marshaler = formatAny{}