Skip to content

Commit 320533c

Browse files
authored
Merge pull request #33155 from vespa-engine/havardpe/vespa-query-profile-option
added profile mode to vespa query (cli command)
2 parents 813350a + 1c63e9e commit 320533c

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

Diff for: client/go/internal/cli/cmd/query.go

+33-12
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)