openconfig / gnmi

gRPC Network Management Interface
Apache License 2.0
478 stars 197 forks source link

How to properely marshal a gNMI struct to string? #78

Closed hellt closed 4 years ago

hellt commented 4 years ago

Hi, I am trying to log a gNMI proto message contents before sending it off to the target, I thought I could use the following:

import (
    "github.com/openconfig/gnmi/proto/gnmi"
    "google.golang.org/protobuf/encoding/prototext"
)
req := &gnmi.GetRequest{
    UseModels: make([]*gnmi.ModelData, 0),
    Path:      make([]*gnmi.Path, 0),
    Encoding:  gnmi.Encoding(encodingVal),
}
logger.Printf("sending gNMI GetRequest: '%s'", prototext.MarshalOptions{Multiline: false}.Format(req))

but unfortunately prototext marshaller fails to recognize (?) all of the fields for this GetRequest, since the output contains only the path information:

2020/06/11 09:08:14.938045 sending gNMI GetRequest: 'path:{elem:{name:"state"} elem:{name:"system"} elem:{name:"version"}}'
robshakir commented 4 years ago

By default, marshalling to textproto will leave out fields that are set to their default value. This will be the case when you set encoding to JSON``, or leave an empty set of fields inuse_modelsorpath`.

Please see the small program here that demonstrates this:

package main

import (
    "fmt"

    gpb "github.com/openconfig/gnmi/proto/gnmi"
    "github.com/openconfig/ygot/ygot"
    "google.golang.org/protobuf/encoding/prototext"
)

func main() {
    // Prints an empty message
    p := &gpb.GetRequest{Path: []*gpb.Path{}}
    fmt.Printf("%s\n", prototext.Format(p))

    // Prints a populated Path field.
    if pp, err := ygot.StringToStructuredPath("/interfaces/interface[name=eth0]/state/oper-status"); err == nil {
        p.Path = []*gpb.Path{pp}
    }
    fmt.Printf("%s\n", prototext.Format(p))

    // Doesn't print the encoding field
    p.Encoding = gpb.Encoding_JSON
    fmt.Printf("%s\n", prototext.Format(p))

    // Prints the encoding field
    p.Encoding = gpb.Encoding_ASCII
    fmt.Printf("%s\n", prototext.Format(p))
}
hellt commented 4 years ago

Thanks @robshakir !

  1. Am I correct that JSON for encoding is considered to be default because it is mapped to int32 0, as well as DataType ALL is mapped to 0
  2. If 1 is correct, is it though true , that on the wire the default value for, say, JSON encoding which is 0 will be still encoded as a slice of bytes when sent over the grpc channel?
robshakir commented 4 years ago
  1. Yes, the 0 value of an enumeration is its default value. This is described here.

  2. The encoding seen by marshalling to textproto is not what is used on the wire -- you can find the full details of the binary encoding here.

hellt commented 4 years ago

Closing, since there is no option to override default behavior of the text marshaller