Charles L.
Charles L.

Reputation: 6295

Does golang provide an easy way to output human readable protobuf

Is there a good way to get a human readable string representation of protobuf objects in golang? Something equivalent to https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message#Message.DebugString?

I am using https://github.com/golang/protobuf.

Upvotes: 12

Views: 22733

Answers (5)

Enrique Junchaya
Enrique Junchaya

Reputation: 63

Since github.com/golang/protobuf is now deprecated, I'm writing this answer for the package google.golang.org/protobuf as it might help new readers.

The prototext package is aimed to convert messages to and from text format. The output is human readable. Using the same example from other answers:

p := &example.Test{
  Label: proto.String("this"),
  Reps:  []int64{4, 3, 2, 1},
  InnerTest: &example.Test_InnerTest{
    InnerLabel: proto.String("is the end"),
  },
}

fmt.Println(prototext.Format(p))

However, I suggest using the protojson package since its outputs are also human readable and it has more options available. For instance, if you want to output all the fields of the message, even those that were not populated, in a human readable manner you can do

p := &example.Test{
  Label: proto.String("this"),
  Reps:  []int64{4, 3, 2, 1},
  InnerTest: &example.Test_InnerTest{
    InnerLabel: proto.String("is the end"),
  },
}

fmt.Println(
    protojson.MarshalOptions{
        Multiline: true, 
        EmitUnpopulated: true,
    }.Format(p)
)

Upvotes: 1

Zombo
Zombo

Reputation: 1

Example one:

package main
import "google.golang.org/protobuf/types/known/structpb"

func example1(x *structpb.Struct) string {
   return x.String()
}

Example two:

package main

import (
   "google.golang.org/protobuf/proto"
   "google.golang.org/protobuf/runtime/protoimpl"
)

func example2(m proto.Message) string {
   return protoimpl.X.MessageStringOf(m)
}

Example three:

package main

import (
   "google.golang.org/protobuf/encoding/protojson"
   "google.golang.org/protobuf/proto"
)

func example3(m proto.Message) string {
   return protojson.Format(m)
}

Test:

package main
import "google.golang.org/protobuf/types/known/structpb"

func main() {
   m, err := structpb.NewStruct(map[string]interface{}{
      "month": 12, "day": 31,
   })
   if err != nil {
      panic(err)
   }
   println(example1(m))
   println(example2(m))
   println(example3(m))
}

Result:

fields:{key:"day" value:{number_value:31}} fields:{key:"month" value:{number_value:12}}
fields:{key:"day" value:{number_value:31}} fields:{key:"month" value:{number_value:12}}
{
  "day": 31,
  "month": 12
}

Upvotes: 4

d0zingcat
d0zingcat

Reputation: 1147

You can use MarshalToString, if you need to marshal your PB into a structured message(in JSON) for future use.

A simple example:

marshaler := &jsonpb.Marshaler{}
reqString, err := marshaler.MarshalToString(req)
log.Println("@@REQ@@", reqString)

Or refer to official unit test is ok.

Upvotes: 1

Pascal Corpet
Pascal Corpet

Reputation: 286

I believe you're looking for proto.MarshalTextString.

p := &example.Test{
  Label: proto.String("this"),
  Reps:  []int64{4, 3, 2, 1},
  InnerTest: &example.Test_InnerTest{
    InnerLabel: proto.String("is the end"),
  },
}

fmt.Println(proto.MarshalTextString(p))

You can see an example in the Go package test.

Upvotes: 19

cnicutar
cnicutar

Reputation: 182664

You can use the TextMarshaler. With a slightly modified example proto:

p := &example.Test{
    Label: proto.String("this"),
    Reps:  []int64{4, 3, 2, 1},
    InnerTest: &example.Test_InnerTest{
        InnerLabel: proto.String("is the end"),
    },
}

t := proto.TextMarshaler{}
t.Marshal(os.Stdout, p)

Outputs:

label: "this"
reps: 4
reps: 3
reps: 2
reps: 1
inner_test: <
  inner_label: "is the end"
>

Upvotes: 4

Related Questions