Print size of the message in very verbose mode (#181)

Adds -vv flag for "very verbose".
Includes estimated message size when enabled. The size is an estimate because it is the canonical size for the proto message, but not necessarily its actual on-the-wire size.
This commit is contained in:
Sergei Vorobev 2020-08-14 08:02:42 -07:00 committed by GitHub
parent 41a6ac0479
commit e544b9e66f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 29 deletions

View File

@ -135,6 +135,8 @@ var (
When describing messages, show a template of input data.`))
verbose = flags.Bool("v", false, prettify(`
Enable verbose output.`))
veryVerbose = flags.Bool("vv", false, prettify(`
Enable very verbose output.`))
serverName = flags.String("servername", "", prettify(`
Override server name when validating TLS certificate. This flag is
ignored if -plaintext or -insecure is used.
@ -316,6 +318,14 @@ func main() {
invoke = true
}
verbosityLevel := 0
if *verbose {
verbosityLevel = 1
}
if *veryVerbose {
verbosityLevel = 2
}
var symbol string
if invoke {
if len(args) == 0 {
@ -651,7 +661,7 @@ func main() {
// if not verbose output, then also include record delimiters
// between each message, so output could potentially be piped
// to another grpcurl process
includeSeparators := !*verbose
includeSeparators := verbosityLevel == 0
options := grpcurl.FormatOptions{
EmitJSONDefaultFields: *emitDefaults,
IncludeTextSeparator: includeSeparators,
@ -661,7 +671,11 @@ func main() {
if err != nil {
fail(err, "Failed to construct request parser and formatter for %q", *format)
}
h := grpcurl.NewDefaultEventHandler(os.Stdout, descSource, formatter, *verbose)
h := &grpcurl.DefaultEventHandler{
Out: os.Stdout,
Formatter: formatter,
VerbosityLevel: verbosityLevel,
}
err = grpcurl.InvokeRPC(ctx, descSource, cc, symbol, append(addlHeaders, rpcHeaders...), h, rf.Next)
if err != nil {
@ -676,7 +690,7 @@ func main() {
if h.NumResponses != 1 {
respSuffix = "s"
}
if *verbose {
if verbosityLevel > 0 {
fmt.Printf("Sent %d request%s and received %d response%s\n", reqCount, reqSuffix, h.NumResponses, respSuffix)
}
if h.Status.Code() != codes.OK {

View File

@ -409,10 +409,12 @@ func RequestParserAndFormatterFor(format Format, descSource DescriptorSource, em
// safe for use with InvokeRPC as long as NumResponses and Status are not read
// until the call to InvokeRPC completes.
type DefaultEventHandler struct {
out io.Writer
descSource DescriptorSource
formatter func(proto.Message) (string, error)
verbose bool
Out io.Writer
Formatter Formatter
// 0 = default
// 1 = verbose
// 2 = very verbose
VerbosityLevel int
// NumResponses is the number of responses that have been received.
NumResponses int
@ -424,54 +426,65 @@ type DefaultEventHandler struct {
// NewDefaultEventHandler returns an InvocationEventHandler that logs events to
// the given output. If verbose is true, all events are logged. Otherwise, only
// response messages are logged.
//
// Deprecated: NewDefaultEventHandler exists for compatability.
// It doesn't allow fine control over the `VerbosityLevel`
// and provides only 0 and 1 options (which corresponds to the `verbose` argument).
// Use DefaultEventHandler{} initializer directly.
func NewDefaultEventHandler(out io.Writer, descSource DescriptorSource, formatter Formatter, verbose bool) *DefaultEventHandler {
verbosityLevel := 0
if verbose {
verbosityLevel = 1
}
return &DefaultEventHandler{
out: out,
descSource: descSource,
formatter: formatter,
verbose: verbose,
Out: out,
Formatter: formatter,
VerbosityLevel: verbosityLevel,
}
}
var _ InvocationEventHandler = (*DefaultEventHandler)(nil)
func (h *DefaultEventHandler) OnResolveMethod(md *desc.MethodDescriptor) {
if h.verbose {
txt, err := GetDescriptorText(md, h.descSource)
if h.VerbosityLevel > 0 {
txt, err := GetDescriptorText(md, nil)
if err == nil {
fmt.Fprintf(h.out, "\nResolved method descriptor:\n%s\n", txt)
fmt.Fprintf(h.Out, "\nResolved method descriptor:\n%s\n", txt)
}
}
}
func (h *DefaultEventHandler) OnSendHeaders(md metadata.MD) {
if h.verbose {
fmt.Fprintf(h.out, "\nRequest metadata to send:\n%s\n", MetadataToString(md))
if h.VerbosityLevel > 0 {
fmt.Fprintf(h.Out, "\nRequest metadata to send:\n%s\n", MetadataToString(md))
}
}
func (h *DefaultEventHandler) OnReceiveHeaders(md metadata.MD) {
if h.verbose {
fmt.Fprintf(h.out, "\nResponse headers received:\n%s\n", MetadataToString(md))
if h.VerbosityLevel > 0 {
fmt.Fprintf(h.Out, "\nResponse headers received:\n%s\n", MetadataToString(md))
}
}
func (h *DefaultEventHandler) OnReceiveResponse(resp proto.Message) {
h.NumResponses++
if h.verbose {
fmt.Fprint(h.out, "\nResponse contents:\n")
if h.VerbosityLevel > 1 {
fmt.Fprintf(h.Out, "\nEstimated response size: %d bytes\n", proto.Size(resp))
}
if respStr, err := h.formatter(resp); err != nil {
fmt.Fprintf(h.out, "Failed to format response message %d: %v\n", h.NumResponses, err)
if h.VerbosityLevel > 0 {
fmt.Fprint(h.Out, "\nResponse contents:\n")
}
if respStr, err := h.Formatter(resp); err != nil {
fmt.Fprintf(h.Out, "Failed to format response message %d: %v\n", h.NumResponses, err)
} else {
fmt.Fprintln(h.out, respStr)
fmt.Fprintln(h.Out, respStr)
}
}
func (h *DefaultEventHandler) OnReceiveTrailers(stat *status.Status, md metadata.MD) {
h.Status = stat
if h.verbose {
fmt.Fprintf(h.out, "\nResponse trailers received:\n%s\n", MetadataToString(md))
if h.VerbosityLevel > 0 {
fmt.Fprintf(h.Out, "\nResponse trailers received:\n%s\n", MetadataToString(md))
}
}

View File

@ -120,12 +120,14 @@ func TestHandler(t *testing.T) {
for _, format := range []Format{FormatJSON, FormatText} {
for _, numMessages := range []int{1, 3} {
for _, verbose := range []bool{true, false} {
for verbosityLevel := 0; verbosityLevel <= 2; verbosityLevel++ {
name := fmt.Sprintf("%s, %d message(s)", format, numMessages)
if verbose {
name += ", verbose"
if verbosityLevel > 0 {
name += fmt.Sprintf(", verbosityLevel=%d", verbosityLevel)
}
verbose := verbosityLevel > 0
_, formatter, err := RequestParserAndFormatter(format, source, nil, FormatOptions{IncludeTextSeparator: !verbose})
if err != nil {
t.Errorf("Failed to create parser and formatter: %v", err)
@ -133,7 +135,11 @@ func TestHandler(t *testing.T) {
}
var buf bytes.Buffer
h := NewDefaultEventHandler(&buf, source, formatter, verbose)
h := &DefaultEventHandler{
Out: &buf,
Formatter: formatter,
VerbosityLevel: verbosityLevel,
}
h.OnResolveMethod(md)
h.OnSendHeaders(reqHeaders)
@ -148,6 +154,9 @@ func TestHandler(t *testing.T) {
expectedOutput += verbosePrefix
}
for i := 0; i < numMessages; i++ {
if verbosityLevel > 1 {
expectedOutput += verboseResponseSize
}
if verbose {
expectedOutput += verboseResponseHeader
}
@ -226,6 +235,9 @@ Response trailers received:
a: 1
b: 2
c: 3
`
verboseResponseSize = `
Estimated response size: 100 bytes
`
verboseResponseHeader = `
Response contents:

2
go.sum
View File

@ -365,6 +365,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@ -444,6 +445,7 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=