Skip to content

Commit 1c63e9e

Browse files
committed
added profile mode to vespa query (cli command)
adjust relevant query parameters and save the result to the given file instead of displaying it to the user.
1 parent 78b09e9 commit 1c63e9e

1 file changed

Lines changed: 33 additions & 12 deletions

File tree

‎client/go/internal/cli/cmd/query.go‎

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ type queryOptions struct {
3131
format string
3232
postFile string
3333
headers []string
34+
profile bool
35+
profileFile string
3436
}
3537

3638
func newQueryCmd(cli *CLI) *cobra.Command {
@@ -62,6 +64,8 @@ can be set by the syntax [parameter-name]=[value].`,
6264
cmd.Flags().StringVarP(&opts.format, "format", "", "human", "Output format. Must be 'human' (human-readable) or 'plain' (no formatting)")
6365
cmd.Flags().StringSliceVarP(&opts.headers, "header", "", nil, "Add a header to the HTTP request, on the format 'Header: Value'. This can be specified multiple times")
6466
cmd.Flags().IntVarP(&opts.queryTimeoutSecs, "timeout", "T", 10, "Timeout for the query in seconds")
67+
cmd.Flags().BoolVarP(&opts.profile, "profile", "", false, "Enable profiling mode (Note: this feature is experimental)")
68+
cmd.Flags().StringVarP(&opts.profileFile, "profile-file", "", "vespa_query_profile_result.json", "Profiling result file")
6569
cli.bindWaitFlag(cmd, 0, &opts.waitSecs)
6670
return cmd
6771
}
@@ -106,6 +110,13 @@ func query(cli *CLI, arguments []string, opts *queryOptions, waiter *Waiter) err
106110
key, value := splitArg(arguments[i])
107111
urlQuery.Set(key, value)
108112
}
113+
if opts.profile {
114+
opts.format = "plain"
115+
opts.queryTimeoutSecs *= 2
116+
urlQuery.Set("trace.level", "1")
117+
urlQuery.Set("trace.explainLevel", "1")
118+
urlQuery.Set("trace.profiling.matching.depth", "100")
119+
}
109120
queryTimeout := urlQuery.Get("timeout")
110121
if queryTimeout == "" {
111122
// No timeout set by user, use the timeout option
@@ -146,7 +157,17 @@ func query(cli *CLI, arguments []string, opts *queryOptions, waiter *Waiter) err
146157
defer response.Body.Close()
147158

148159
if response.StatusCode == 200 {
149-
if err := printResponse(response.Body, response.Header.Get("Content-Type"), opts.format, cli); err != nil {
160+
var output io.Writer = cli.Stdout
161+
if opts.profile {
162+
profileFile, err := os.Create(opts.profileFile)
163+
if err != nil {
164+
return fmt.Errorf("failed to create profile file %s: %w", opts.profileFile, err)
165+
}
166+
defer profileFile.Close()
167+
fmt.Fprintf(cli.Stderr, "writing profiling results to: %s\n", opts.profileFile)
168+
output = profileFile
169+
}
170+
if err := printResponse(response.Body, response.Header.Get("Content-Type"), opts.format, output); err != nil {
150171
return err
151172
}
152173
} else if response.StatusCode/100 == 4 {
@@ -157,15 +178,15 @@ func query(cli *CLI, arguments []string, opts *queryOptions, waiter *Waiter) err
157178
return nil
158179
}
159180

160-
func printResponse(body io.Reader, contentType, format string, cli *CLI) error {
181+
func printResponse(body io.Reader, contentType, format string, output io.Writer) error {
161182
contentType = strings.Split(contentType, ";")[0]
162183
if contentType == "text/event-stream" {
163184
return printResponseBody(body, printOptions{
164185
plainStream: format == "plain",
165186
tokenStream: format == "human",
166-
}, cli)
187+
}, output)
167188
}
168-
return printResponseBody(body, printOptions{parseJSON: format == "human"}, cli)
189+
return printResponseBody(body, printOptions{parseJSON: format == "human"}, output)
169190
}
170191

171192
type printOptions struct {
@@ -174,9 +195,9 @@ type printOptions struct {
174195
parseJSON bool
175196
}
176197

177-
func printResponseBody(body io.Reader, options printOptions, cli *CLI) error {
198+
func printResponseBody(body io.Reader, options printOptions, output io.Writer) error {
178199
if options.plainStream {
179-
_, err := io.Copy(cli.Stdout, body)
200+
_, err := io.Copy(output, body)
180201
return err
181202
} else if options.tokenStream {
182203
bufSize := 1024 * 1024 // Handle events up to this size
@@ -200,29 +221,29 @@ func printResponseBody(body io.Reader, options printOptions, cli *CLI) error {
200221
if err := json.Unmarshal([]byte(event.Data), &token); err == nil {
201222
value = token.Value
202223
}
203-
fmt.Fprint(cli.Stdout, value)
224+
fmt.Fprint(output, value)
204225
} else if !event.IsEnd() {
205226
if writingLine {
206-
fmt.Fprintln(cli.Stdout)
227+
fmt.Fprintln(output)
207228
}
208229
event.Data = ioutil.StringToJSON(event.Data) // Optimistically pretty-print JSON
209-
fmt.Fprint(cli.Stdout, event.String())
230+
fmt.Fprint(output, event.String())
210231
} else {
211-
fmt.Fprintln(cli.Stdout)
232+
fmt.Fprintln(output)
212233
break
213234
}
214235
}
215236
return nil
216237
} else if options.parseJSON {
217238
text := ioutil.ReaderToJSON(body) // Optimistic, returns body as the raw string if it cannot be parsed to JSON
218-
fmt.Fprintln(cli.Stdout, text)
239+
fmt.Fprintln(output, text)
219240
return nil
220241
} else {
221242
b, err := io.ReadAll(body)
222243
if err != nil {
223244
return err
224245
}
225-
fmt.Fprintln(cli.Stdout, string(b))
246+
fmt.Fprintln(output, string(b))
226247
return nil
227248
}
228249
}

0 commit comments

Comments
 (0)