From 76391434c25e054dea2a56d2e73e2178483e549a Mon Sep 17 00:00:00 2001 From: Devin Carr Date: Tue, 25 Apr 2023 17:13:16 -0700 Subject: [PATCH] TUN-7393: Add json output for cloudflared tail cloudflared tail now has a `--output=json` that will allow it to easily pipe into tools like jq for a more structured view of the streaming logs. --- cmd/cloudflared/tail/cmd.go | 43 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/cmd/cloudflared/tail/cmd.go b/cmd/cloudflared/tail/cmd.go index 19323564..7d444024 100644 --- a/cmd/cloudflared/tail/cmd.go +++ b/cmd/cloudflared/tail/cmd.go @@ -99,6 +99,12 @@ func buildTailCommand(subcommands []*cli.Command) *cli.Command { Value: "", EnvVars: []string{"TUNNEL_MANAGEMENT_TOKEN"}, }, + &cli.StringFlag{ + Name: "output", + Usage: "Output format for the logs (default, json)", + Value: "default", + EnvVars: []string{"TUNNEL_MANAGEMENT_OUTPUT"}, + }, &cli.StringFlag{ Name: "management-hostname", Usage: "Management hostname to signify incoming management requests", @@ -270,6 +276,24 @@ func buildURL(c *cli.Context, log *zerolog.Logger) (url.URL, error) { return url.URL{Scheme: "wss", Host: managementHostname, Path: "/logs", RawQuery: query.Encode()}, nil } +func printLine(log *management.Log, logger *zerolog.Logger) { + fields, err := json.Marshal(log.Fields) + if err != nil { + fields = []byte("unable to parse fields") + logger.Debug().Msgf("unable to parse fields from event %+v", log) + } + fmt.Printf("%s %s %s %s %s\n", log.Time, log.Level, log.Event, log.Message, fields) +} + +func printJSON(log *management.Log, logger *zerolog.Logger) { + output, err := json.Marshal(log) + if err != nil { + logger.Debug().Msgf("unable to parse event to json %+v", log) + } else { + fmt.Println(string(output)) + } +} + // Run implements a foreground runner func Run(c *cli.Context) error { log := createLogger(c) @@ -278,6 +302,16 @@ func Run(c *cli.Context) error { signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) defer signal.Stop(signals) + output := "default" + switch c.String("output") { + case "default", "": + output = "default" + case "json": + output = "json" + default: + log.Err(errors.New("invalid --output value provided, please make sure it is one of: default, json")).Send() + } + filters, err := parseFilters(c) if err != nil { log.Error().Err(err).Msgf("invalid filters provided") @@ -358,12 +392,11 @@ func Run(c *cli.Context) error { } // Output all the logs received to stdout for _, l := range logs.Logs { - fields, err := json.Marshal(l.Fields) - if err != nil { - fields = []byte("unable to parse fields") - log.Debug().Msgf("unable to parse fields from event %+v", l) + if output == "json" { + printJSON(l, log) + } else { + printLine(l, log) } - fmt.Printf("%s %s %s %s %s\n", l.Time, l.Level, l.Event, l.Message, fields) } case management.UnknownServerEventType: fallthrough