diff options
author | Martin Polden <mpolden@mpolden.no> | 2021-09-28 14:59:57 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2021-09-29 08:53:14 +0200 |
commit | 7e9e07995ce83e148cd62d0eb7dbecdad8bcac77 (patch) | |
tree | 7da52ef275949082109224255fe6f4a62dd86852 /client | |
parent | 04d529f9b7c6ec02ececf667f441c7de2247d3ee (diff) |
Implement vespa log command
Diffstat (limited to 'client')
-rw-r--r-- | client/go/cmd/log.go | 97 | ||||
-rw-r--r-- | client/go/cmd/log_test.go | 27 |
2 files changed, 124 insertions, 0 deletions
diff --git a/client/go/cmd/log.go b/client/go/cmd/log.go new file mode 100644 index 00000000000..acfeef0e71f --- /dev/null +++ b/client/go/cmd/log.go @@ -0,0 +1,97 @@ +package cmd + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + "github.com/vespa-engine/vespa/client/go/vespa" +) + +var ( + fromArg string + toArg string + levelArg string + followArg bool + dequoteArg bool +) + +func init() { + rootCmd.AddCommand(logCmd) + logCmd.Flags().StringVarP(&fromArg, "from", "F", "", "Include logs since this timestamp (RFC3339 format)") + logCmd.Flags().StringVarP(&toArg, "to", "T", "", "Include logs until this timestamp (RFC3339 format)") + logCmd.Flags().StringVarP(&levelArg, "level", "l", "debug", `The maximum log level to show. Must be "error", "warning", "info" or "debug"`) + logCmd.Flags().BoolVarP(&followArg, "follow", "f", false, "Follow logs") + logCmd.Flags().BoolVarP(&dequoteArg, "nldequote", "n", true, "Dequote LF and TAB characters in log messages") +} + +var logCmd = &cobra.Command{ + Use: "log [relative-period]", + Short: "Show the Vespa log", + Long: `Show the Vespa log. + +The logs shown can be limited to a relative or fixed period. All timestamps are shown in UTC. +`, + Example: `$ vespa log 1h +$ vespa log --nldequote=false 10m +$ vespa log --from 2021-08-25T15:00:00Z --to 2021-08-26T02:00:00Z +$ vespa log --follow`, + DisableAutoGenTag: true, + Args: cobra.MaximumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + target := getTarget() + options := vespa.LogOptions{ + Level: vespa.LogLevel(levelArg), + Follow: followArg, + Writer: stdout, + Dequote: dequoteArg, + } + if options.Follow { + if fromArg != "" || toArg != "" || len(args) > 0 { + fatalErr(fmt.Errorf("cannot combine --from/--to or relative time with --follow"), "Could not follow logs") + } + options.From = time.Now().Add(-5 * time.Minute) + } else { + from, to, err := parsePeriod(args) + if err != nil { + fatalErr(err, "Invalid period") + return + } + options.From = from + options.To = to + } + if err := target.PrintLog(options); err != nil { + fatalErr(err, "Could not retrieve logs") + } + }, +} + +func parsePeriod(args []string) (time.Time, time.Time, error) { + if len(args) == 1 { + if fromArg != "" || toArg != "" { + return time.Time{}, time.Time{}, fmt.Errorf("cannot combine --from/--to with relative value: %s", args[0]) + } + d, err := time.ParseDuration(args[0]) + if err != nil { + return time.Time{}, time.Time{}, err + } + if d > 0 { + d = -d + } + to := time.Now() + from := to.Add(d) + return from, to, nil + } + from, err := time.Parse(time.RFC3339, fromArg) + if err != nil { + return time.Time{}, time.Time{}, err + } + to, err := time.Parse(time.RFC3339, toArg) + if err != nil { + return time.Time{}, time.Time{}, err + } + if !to.After(from) { + return time.Time{}, time.Time{}, fmt.Errorf("--to must specify a time after --from") + } + return from, to, nil +} diff --git a/client/go/cmd/log_test.go b/client/go/cmd/log_test.go new file mode 100644 index 00000000000..a4660001ec4 --- /dev/null +++ b/client/go/cmd/log_test.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLog(t *testing.T) { + homeDir := filepath.Join(t.TempDir(), ".vespa") + pkgDir := mockApplicationPackage(t, false) + httpClient := &mockHttpClient{} + httpClient.NextResponse(200, `1632738690.905535 host1a.dev.aws-us-east-1c 806/53 logserver-container Container.com.yahoo.container.jdisc.ConfiguredApplication info Switching to the latest deployed set of configurations and components. Application config generation: 52532`) + execute(command{homeDir: homeDir, args: []string{"config", "set", "application", "t1.a1.i1"}}, t, httpClient) + execute(command{homeDir: homeDir, args: []string{"config", "set", "target", "cloud"}}, t, httpClient) + execute(command{homeDir: homeDir, args: []string{"api-key"}}, t, httpClient) + execute(command{homeDir: homeDir, args: []string{"cert", pkgDir}}, t, httpClient) + + out, _ := execute(command{homeDir: homeDir, args: []string{"log", "--from", "2021-09-27T10:00:00Z", "--to", "2021-09-27T11:00:00Z"}}, t, httpClient) + + expected := "[2021-09-27 10:31:30.905535] host1a.dev.aws-us-east-1c info logserver-container Container.com.yahoo.container.jdisc.ConfiguredApplication Switching to the latest deployed set of configurations and components. Application config generation: 52532\n" + assert.Equal(t, expected, out) + + out, _ = execute(command{homeDir: homeDir, args: []string{"log", "--from", "2021-09-27T13:12:49Z", "--to", "2021-09-27T13:15:00", "1h"}}, t, httpClient) + assert.Equal(t, "Error: Invalid period\ncannot combine --from/--to with relative value: 1h\n", out) +} |