1 /* 2 * 3 * Copyright 2021 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package pretty defines helper functions to pretty-print structs for logging. 20 package pretty 21 22 import ( 23 "bytes" 24 "encoding/json" 25 "fmt" 26 27 "google.golang.org/protobuf/encoding/protojson" 28 "google.golang.org/protobuf/protoadapt" 29 ) 30 31 const jsonIndent = " " 32 33 // ToJSON marshals the input into a json string. 34 // 35 // If marshal fails, it falls back to fmt.Sprintf("%+v"). 36 func ToJSON(e any) string { 37 if ee, ok := e.(protoadapt.MessageV1); ok { 38 e = protoadapt.MessageV2Of(ee) 39 } 40 41 if ee, ok := e.(protoadapt.MessageV2); ok { 42 mm := protojson.MarshalOptions{ 43 Indent: jsonIndent, 44 Multiline: true, 45 } 46 ret, err := mm.Marshal(ee) 47 if err != nil { 48 // This may fail for proto.Anys, e.g. for xDS v2, LDS, the v2 49 // messages are not imported, and this will fail because the message 50 // is not found. 51 return fmt.Sprintf("%+v", ee) 52 } 53 return string(ret) 54 } 55 56 ret, err := json.MarshalIndent(e, "", jsonIndent) 57 if err != nil { 58 return fmt.Sprintf("%+v", e) 59 } 60 return string(ret) 61 } 62 63 // FormatJSON formats the input json bytes with indentation. 64 // 65 // If Indent fails, it returns the unchanged input as string. 66 func FormatJSON(b []byte) string { 67 var out bytes.Buffer 68 err := json.Indent(&out, b, "", jsonIndent) 69 if err != nil { 70 return string(b) 71 } 72 return out.String() 73 } 74