diff --git a/cmd/grpcurl/grpcurl.go b/cmd/grpcurl/grpcurl.go index e1fd37b..d7bb65f 100644 --- a/cmd/grpcurl/grpcurl.go +++ b/cmd/grpcurl/grpcurl.go @@ -95,8 +95,8 @@ var ( connectTimeout = flags.Float64("connect-timeout", 0, prettify(` The maximum time, in seconds, to wait for connection to be established. Defaults to 10 seconds.`)) - jsonError = flags.Bool("json-error", false, prettify(` - Emit error response as JSON.`)) + errorFormat = flags.String("error-format", "text", prettify(` + The format of request data. The allowed values are 'json' or 'text'.`)) keepaliveTime = flags.Float64("keepalive-time", 0, prettify(` If present, the maximum idle time in seconds, after which a keepalive probe is sent. If the connection remains idle and no keepalive response @@ -272,7 +272,10 @@ func main() { fail(nil, "The -cert and -key arguments must be used together and both be present.") } if *format != "json" && *format != "text" { - fail(nil, "The -format option must be 'json' or 'text.") + fail(nil, "The -format option must be 'json' or 'text'.") + } + if *errorFormat != "json" && *errorFormat != "text" { + fail(nil, "The -error-format option must be 'json' or 'text'.") } if *emitDefaults && *format != "json" { warn("The -emit-defaults is only used when using json format.") @@ -654,11 +657,7 @@ func main() { fmt.Printf("Sent %d request%s and received %d response%s\n", reqCount, reqSuffix, h.NumResponses, respSuffix) } if h.Status.Code() != codes.OK { - if *jsonError { - grpcurl.PrintJSONStatus(os.Stderr, h.Status) - } else { - grpcurl.PrintStatus(os.Stderr, h.Status, formatter) - } + grpcurl.HandleFormatAndPrintStatus(grpcurl.Format(*errorFormat), os.Stderr, h.Status, formatter) exit(1) } } diff --git a/format.go b/format.go index bc40b69..9d61ed9 100644 --- a/format.go +++ b/format.go @@ -429,6 +429,21 @@ func (h *DefaultEventHandler) OnReceiveTrailers(stat *status.Status, md metadata } } +// HandleFormatAndPrintStatus passes the writer, status object, and formatter (if applicable) +// to the appropriate status printing function +func HandleFormatAndPrintStatus(format Format, w io.Writer, stat *status.Status, formatter Formatter) { + + switch format { + case FormatJSON: + marshaler := jsonpb.Marshaler{Indent: " "} + PrintFormattedStatus(w, stat, marshaler.MarshalToString) + case FormatText: + PrintStatus(w, stat, formatter) + default: + fmt.Errorf("unknown format: %s", format) + } +} + // PrintStatus prints details about the given status to the given writer. The given // formatter is used to print any detail messages that may be included in the status. // If the given status has a code of OK, "OK" is printed and that is all. Otherwise, @@ -468,9 +483,10 @@ func PrintStatus(w io.Writer, stat *status.Status, formatter Formatter) { } } -// PrintJSONStatus returns the grpc status response as a JSON object -func PrintJSONStatus(w io.Writer, stat *status.Status) { - jsonStatus, err := (&jsonpb.Marshaler{}).MarshalToString(stat.Proto()) +// PrintFormattedStatus writes the gRPC status response in its entirety given the +// provided Formatter +func PrintFormattedStatus(w io.Writer, stat *status.Status, formatter Formatter) { + jsonStatus, err := formatter(stat.Proto()) if err != nil { fmt.Fprintf(w, "ERROR: %v", err.Error()) } diff --git a/format_test.go b/format_test.go index f767ef3..459392c 100644 --- a/format_test.go +++ b/format_test.go @@ -175,7 +175,7 @@ func TestHandler(t *testing.T) { } } -func TestPrintJSONStatus(t *testing.T) { +func TestPrintFormattedStatus(t *testing.T) { testCases := []struct { input *status.Status expectedOutput string @@ -186,7 +186,7 @@ func TestPrintJSONStatus(t *testing.T) { for _, tc := range testCases { var b bytes.Buffer - PrintJSONStatus(&b, tc.input) + HandleFormatAndPrintStatus(FormatJSON, &b, tc.input, nil) got := b.String() if !compare(tc.expectedOutput, got) { t.Errorf("Incorrect output. Expected:\n%s\nGot:\n%s", tc.expectedOutput, got) @@ -265,7 +265,10 @@ Response contents: "null": null } ` - statusAsJSON = `{"code":3,"message":"Missing Argument"} ` + statusAsJSON = `{ + "code": 3, + "message": "Missing Argument" +}` messageAsText = `struct_value: < fields: < key: "bar"