pretty.go

 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.
20package pretty
21
22import (
23	"bytes"
24	"encoding/json"
25	"fmt"
26
27	"google.golang.org/protobuf/encoding/protojson"
28	"google.golang.org/protobuf/protoadapt"
29)
30
31const jsonIndent = "  "
32
33// ToJSON marshals the input into a json string.
34//
35// If marshal fails, it falls back to fmt.Sprintf("%+v").
36func 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.
66func 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}