blob: a846c55d62e08f928c83132c2a3d5d71df6903f1 [file] [log] [blame]
Robin Thellend18205cf2014-10-21 13:53:59 -07001package main
Robin Thellend663bf482014-10-01 10:27:10 -07002
3import (
4 "bytes"
5 "fmt"
Robin Thellend663bf482014-10-01 10:27:10 -07006 "os"
7 "os/exec"
8 "regexp"
9 "sort"
10 "strings"
Robin Thellendfaa083a2014-10-22 13:41:18 -070011 "sync"
Robin Thellenda930f5a2014-10-07 09:54:25 -070012 "time"
Robin Thellend663bf482014-10-01 10:27:10 -070013
Jiri Simsa764efb72014-12-25 20:57:03 -080014 "v.io/core/veyron/lib/glob"
15 "v.io/core/veyron/lib/signals"
16 "v.io/core/veyron/services/mgmt/pprof/client"
17 istats "v.io/core/veyron/services/mgmt/stats"
Matt Rosencrantzd599e382015-01-12 11:13:32 -080018 "v.io/core/veyron2"
Jiri Simsa764efb72014-12-25 20:57:03 -080019 "v.io/core/veyron2/context"
20 "v.io/core/veyron2/naming"
21 "v.io/core/veyron2/services/mgmt/logreader"
22 logtypes "v.io/core/veyron2/services/mgmt/logreader/types"
23 "v.io/core/veyron2/services/mgmt/pprof"
24 "v.io/core/veyron2/services/mgmt/stats"
25 vtracesvc "v.io/core/veyron2/services/mgmt/vtrace"
26 "v.io/core/veyron2/services/watch"
27 watchtypes "v.io/core/veyron2/services/watch/types"
28 "v.io/core/veyron2/uniqueid"
Jiri Simsa764efb72014-12-25 20:57:03 -080029 "v.io/core/veyron2/vtrace"
Todd Wang478fcf92014-12-26 12:37:37 -080030 "v.io/lib/cmdline"
Robin Thellend663bf482014-10-01 10:27:10 -070031)
32
33var (
34 follow bool
35 verbose bool
36 numEntries int
37 startPos int64
38 raw bool
39 showType bool
40 pprofCmd string
41)
42
43func init() {
Robin Thellend663bf482014-10-01 10:27:10 -070044 // logs read flags
Robin Thellendfaa083a2014-10-22 13:41:18 -070045 cmdLogsRead.Flags.BoolVar(&follow, "f", false, "When true, read will wait for new log entries when it reaches the end of the file.")
46 cmdLogsRead.Flags.BoolVar(&verbose, "v", false, "When true, read will be more verbose.")
47 cmdLogsRead.Flags.IntVar(&numEntries, "n", int(logtypes.AllEntries), "The number of log entries to read.")
48 cmdLogsRead.Flags.Int64Var(&startPos, "o", 0, "The position, in bytes, from which to start reading the log file.")
Robin Thellend663bf482014-10-01 10:27:10 -070049
Robin Thellendfaa083a2014-10-22 13:41:18 -070050 // stats read flags
51 cmdStatsRead.Flags.BoolVar(&raw, "raw", false, "When true, the command will display the raw value of the object.")
52 cmdStatsRead.Flags.BoolVar(&showType, "type", false, "When true, the type of the values will be displayed.")
Robin Thellend663bf482014-10-01 10:27:10 -070053
Robin Thellendfaa083a2014-10-22 13:41:18 -070054 // stats watch flags
55 cmdStatsWatch.Flags.BoolVar(&raw, "raw", false, "When true, the command will display the raw value of the object.")
56 cmdStatsWatch.Flags.BoolVar(&showType, "type", false, "When true, the type of the values will be displayed.")
Robin Thellend663bf482014-10-01 10:27:10 -070057
58 // pprof flags
Jing Jin06d0dd62014-12-26 15:29:56 -080059 cmdPProfRun.Flags.StringVar(&pprofCmd, "pprofcmd", "v23 go tool pprof", "The pprof command to use.")
Robin Thellend663bf482014-10-01 10:27:10 -070060}
61
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -080062var cmdVtrace = &cmdline.Command{
63 Run: runVtrace,
64 Name: "vtrace",
65 Short: "Returns vtrace traces.",
66 Long: "Returns matching vtrace traces (or all stored traces if no ids are given).",
67 ArgsName: "<name> [id ...]",
68 ArgsLong: `
69<name> is the name of a vtrace object.
70[id] is a vtrace trace id.
71`,
72}
73
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -080074func doFetchTrace(ctx *context.T, wg *sync.WaitGroup, client vtracesvc.StoreClientStub,
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -080075 id uniqueid.ID, traces chan *vtrace.TraceRecord, errors chan error) {
76 defer wg.Done()
77
78 trace, err := client.Trace(ctx, id)
79 if err != nil {
80 errors <- err
81 } else {
82 traces <- &trace
83 }
84}
85
86func runVtrace(cmd *cmdline.Command, args []string) error {
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -080087 arglen := len(args)
88 if arglen == 0 {
89 return cmd.UsageErrorf("vtrace: incorrect number of arguments, got %d want >= 1", arglen)
90 }
91
92 name := args[0]
93 client := vtracesvc.StoreClient(name)
94 if arglen == 1 {
Matt Rosencrantza5ad2722015-01-22 11:17:47 -080095 call, err := client.AllTraces(gctx)
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -080096 if err != nil {
97 return err
98 }
99 stream := call.RecvStream()
100 for stream.Advance() {
101 trace := stream.Value()
102 vtrace.FormatTrace(os.Stdout, &trace, nil)
103 }
104 if err := stream.Err(); err != nil {
105 return err
106 }
107 return call.Finish()
108 }
109
110 ntraces := len(args) - 1
111 traces := make(chan *vtrace.TraceRecord, ntraces)
112 errors := make(chan error, ntraces)
113 var wg sync.WaitGroup
114 wg.Add(ntraces)
115 for _, arg := range args[1:] {
116 id, err := uniqueid.FromHexString(arg)
117 if err != nil {
118 return err
119 }
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800120 go doFetchTrace(gctx, &wg, client, id, traces, errors)
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -0800121 }
122 go func() {
123 wg.Wait()
124 close(traces)
125 close(errors)
126 }()
127
128 for trace := range traces {
129 vtrace.FormatTrace(os.Stdout, trace, nil)
130 }
131
132 // Just return one of the errors.
133 return <-errors
134}
135
Robin Thellend663bf482014-10-01 10:27:10 -0700136var cmdGlob = &cmdline.Command{
137 Run: runGlob,
138 Name: "glob",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700139 Short: "Returns all matching entries from the namespace.",
Robin Thellend663bf482014-10-01 10:27:10 -0700140 Long: "Returns all matching entries from the namespace.",
141 ArgsName: "<pattern> ...",
142 ArgsLong: `
143<pattern> is a glob pattern to match.
144`,
145}
146
147func runGlob(cmd *cmdline.Command, args []string) error {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700148 if min, got := 1, len(args); got < min {
149 return cmd.UsageErrorf("glob: incorrect number of arguments, got %d, want >=%d", got, min)
Robin Thellend663bf482014-10-01 10:27:10 -0700150 }
Robin Thellenda930f5a2014-10-07 09:54:25 -0700151 results := make(chan naming.MountEntry)
Robin Thellend663bf482014-10-01 10:27:10 -0700152 errors := make(chan error)
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800153 doGlobs(gctx, args, results, errors)
Robin Thellend663bf482014-10-01 10:27:10 -0700154 var lastErr error
Robin Thellend663bf482014-10-01 10:27:10 -0700155 for {
156 select {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700157 case err := <-errors:
158 lastErr = err
159 fmt.Fprintln(cmd.Stderr(), "Error:", err)
160 case me, ok := <-results:
161 if !ok {
162 return lastErr
163 }
164 fmt.Fprint(cmd.Stdout(), me.Name)
165 for _, s := range me.Servers {
David Why Use Two When One Will Do Presotto59a254c2014-10-30 13:09:29 -0700166 fmt.Fprintf(cmd.Stdout(), " %s (Expires %s)", s.Server, s.Expires)
Robin Thellend663bf482014-10-01 10:27:10 -0700167 }
168 fmt.Fprintln(cmd.Stdout())
Robin Thellend663bf482014-10-01 10:27:10 -0700169 }
170 }
Robin Thellend663bf482014-10-01 10:27:10 -0700171}
172
Robin Thellendfaa083a2014-10-22 13:41:18 -0700173// doGlobs calls Glob on multiple patterns in parallel and sends all the results
174// on the results channel and all the errors on the errors channel. It closes
175// the results channel when all the results have been sent.
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -0800176func doGlobs(ctx *context.T, patterns []string, results chan<- naming.MountEntry, errors chan<- error) {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700177 var wg sync.WaitGroup
178 wg.Add(len(patterns))
179 for _, p := range patterns {
180 go doGlob(ctx, p, results, errors, &wg)
181 }
182 go func() {
183 wg.Wait()
184 close(results)
185 }()
186}
187
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -0800188func doGlob(ctx *context.T, pattern string, results chan<- naming.MountEntry, errors chan<- error, wg *sync.WaitGroup) {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700189 defer wg.Done()
Matt Rosencrantz89445a42015-01-05 13:32:37 -0800190 ctx, cancel := context.WithTimeout(ctx, time.Minute)
Robin Thellenda930f5a2014-10-07 09:54:25 -0700191 defer cancel()
Matt Rosencrantzd599e382015-01-12 11:13:32 -0800192 c, err := veyron2.GetNamespace(ctx).Glob(ctx, pattern)
Robin Thellend663bf482014-10-01 10:27:10 -0700193 if err != nil {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700194 errors <- fmt.Errorf("%s: %v", pattern, err)
Robin Thellend663bf482014-10-01 10:27:10 -0700195 return
196 }
Robin Thellendfaa083a2014-10-22 13:41:18 -0700197 for me := range c {
198 results <- me
Robin Thellend663bf482014-10-01 10:27:10 -0700199 }
Robin Thellend663bf482014-10-01 10:27:10 -0700200}
201
Robin Thellendfaa083a2014-10-22 13:41:18 -0700202var cmdLogsRead = &cmdline.Command{
203 Run: runLogsRead,
Robin Thellend663bf482014-10-01 10:27:10 -0700204 Name: "read",
205 Short: "Reads the content of a log file object.",
206 Long: "Reads the content of a log file object.",
207 ArgsName: "<name>",
208 ArgsLong: `
209<name> is the name of the log file object.
210`,
211}
212
Robin Thellendfaa083a2014-10-22 13:41:18 -0700213func runLogsRead(cmd *cmdline.Command, args []string) error {
Robin Thellend663bf482014-10-01 10:27:10 -0700214 if want, got := 1, len(args); want != got {
215 return cmd.UsageErrorf("read: incorrect number of arguments, got %d, want %d", got, want)
216 }
217 name := args[0]
Todd Wang702385a2014-11-07 01:54:08 -0800218 lf := logreader.LogFileClient(name)
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800219 stream, err := lf.ReadLog(gctx, startPos, int32(numEntries), follow)
Robin Thellend663bf482014-10-01 10:27:10 -0700220 if err != nil {
221 return err
222 }
223 iterator := stream.RecvStream()
224 for iterator.Advance() {
225 entry := iterator.Value()
226 if verbose {
227 fmt.Fprintf(cmd.Stdout(), "[%d] %s\n", entry.Position, entry.Line)
228 } else {
229 fmt.Fprintf(cmd.Stdout(), "%s\n", entry.Line)
230 }
231 }
232 if err = iterator.Err(); err != nil {
233 return err
234 }
235 offset, err := stream.Finish()
236 if err != nil {
237 return err
238 }
239 if verbose {
240 fmt.Fprintf(cmd.Stdout(), "Offset: %d\n", offset)
241 }
242 return nil
243}
244
Robin Thellendfaa083a2014-10-22 13:41:18 -0700245var cmdLogsSize = &cmdline.Command{
246 Run: runLogsSize,
Robin Thellend663bf482014-10-01 10:27:10 -0700247 Name: "size",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700248 Short: "Returns the size of a log file object.",
249 Long: "Returns the size of a log file object.",
Robin Thellend663bf482014-10-01 10:27:10 -0700250 ArgsName: "<name>",
251 ArgsLong: `
252<name> is the name of the log file object.
253`,
254}
255
Robin Thellendfaa083a2014-10-22 13:41:18 -0700256func runLogsSize(cmd *cmdline.Command, args []string) error {
Robin Thellend663bf482014-10-01 10:27:10 -0700257 if want, got := 1, len(args); want != got {
258 return cmd.UsageErrorf("size: incorrect number of arguments, got %d, want %d", got, want)
259 }
260 name := args[0]
Todd Wang702385a2014-11-07 01:54:08 -0800261 lf := logreader.LogFileClient(name)
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800262 size, err := lf.Size(gctx)
Robin Thellend663bf482014-10-01 10:27:10 -0700263 if err != nil {
264 return err
265 }
266 fmt.Fprintln(cmd.Stdout(), size)
267 return nil
268}
269
Robin Thellendfaa083a2014-10-22 13:41:18 -0700270var cmdStatsRead = &cmdline.Command{
271 Run: runStatsRead,
272 Name: "read",
273 Short: "Returns the value of stats objects.",
274 Long: "Returns the value of stats objects.",
275 ArgsName: "<name> ...",
Robin Thellend663bf482014-10-01 10:27:10 -0700276 ArgsLong: `
Robin Thellendfaa083a2014-10-22 13:41:18 -0700277<name> is the name of a stats object, or a glob pattern to match against stats
278object names.
Robin Thellend663bf482014-10-01 10:27:10 -0700279`,
280}
281
Robin Thellendfaa083a2014-10-22 13:41:18 -0700282func runStatsRead(cmd *cmdline.Command, args []string) error {
283 if min, got := 1, len(args); got < min {
284 return cmd.UsageErrorf("read: incorrect number of arguments, got %d, want >=%d", got, min)
Robin Thellend663bf482014-10-01 10:27:10 -0700285 }
Robin Thellendfaa083a2014-10-22 13:41:18 -0700286 globResults := make(chan naming.MountEntry)
287 errors := make(chan error)
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800288 doGlobs(gctx, args, globResults, errors)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700289
290 output := make(chan string)
291 go func() {
292 var wg sync.WaitGroup
293 for me := range globResults {
294 wg.Add(1)
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800295 go doValue(gctx, me.Name, output, errors, &wg)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700296 }
297 wg.Wait()
298 close(output)
299 }()
300
301 var lastErr error
302 for {
303 select {
304 case err := <-errors:
305 lastErr = err
306 fmt.Fprintln(cmd.Stderr(), err)
307 case out, ok := <-output:
308 if !ok {
309 return lastErr
310 }
311 fmt.Fprintln(cmd.Stdout(), out)
312 }
Robin Thellend663bf482014-10-01 10:27:10 -0700313 }
Robin Thellend663bf482014-10-01 10:27:10 -0700314}
315
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -0800316func doValue(ctx *context.T, name string, output chan<- string, errors chan<- error, wg *sync.WaitGroup) {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700317 defer wg.Done()
Matt Rosencrantz89445a42015-01-05 13:32:37 -0800318 ctx, cancel := context.WithTimeout(ctx, time.Minute)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700319 defer cancel()
Todd Wang702385a2014-11-07 01:54:08 -0800320 v, err := stats.StatsClient(name).Value(ctx)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700321 if err != nil {
322 errors <- fmt.Errorf("%s: %v", name, err)
323 return
324 }
325 output <- fmt.Sprintf("%s: %v", name, formatValue(v))
326}
327
328var cmdStatsWatch = &cmdline.Command{
329 Run: runStatsWatch,
330 Name: "watch",
331 Short: "Returns a stream of all matching entries and their values as they change.",
332 Long: "Returns a stream of all matching entries and their values as they change.",
Robin Thellend663bf482014-10-01 10:27:10 -0700333 ArgsName: "<pattern> ...",
334 ArgsLong: `
335<pattern> is a glob pattern to match.
336`,
337}
338
Robin Thellendfaa083a2014-10-22 13:41:18 -0700339func runStatsWatch(cmd *cmdline.Command, args []string) error {
Robin Thellend663bf482014-10-01 10:27:10 -0700340 if want, got := 1, len(args); got < want {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700341 return cmd.UsageErrorf("watch: incorrect number of arguments, got %d, want >=%d", got, want)
Robin Thellend663bf482014-10-01 10:27:10 -0700342 }
343
344 results := make(chan string)
345 errors := make(chan error)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700346 var wg sync.WaitGroup
347 wg.Add(len(args))
348 for _, arg := range args {
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800349 go doWatch(gctx, arg, results, errors, &wg)
Robin Thellend663bf482014-10-01 10:27:10 -0700350 }
Robin Thellendfaa083a2014-10-22 13:41:18 -0700351 go func() {
352 wg.Wait()
353 close(results)
354 }()
Robin Thellend663bf482014-10-01 10:27:10 -0700355 var lastErr error
Robin Thellend663bf482014-10-01 10:27:10 -0700356 for {
357 select {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700358 case err := <-errors:
359 lastErr = err
360 fmt.Fprintln(cmd.Stderr(), "Error:", err)
361 case r, ok := <-results:
362 if !ok {
363 return lastErr
364 }
Robin Thellend663bf482014-10-01 10:27:10 -0700365 fmt.Fprintln(cmd.Stdout(), r)
Robin Thellend663bf482014-10-01 10:27:10 -0700366 }
367 }
Robin Thellend663bf482014-10-01 10:27:10 -0700368}
369
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -0800370func doWatch(ctx *context.T, pattern string, results chan<- string, errors chan<- error, wg *sync.WaitGroup) {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700371 defer wg.Done()
Robin Thellend663bf482014-10-01 10:27:10 -0700372 root, globPattern := naming.SplitAddressName(pattern)
373 g, err := glob.Parse(globPattern)
374 if err != nil {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700375 errors <- fmt.Errorf("%s: %v", globPattern, err)
Robin Thellend663bf482014-10-01 10:27:10 -0700376 return
377 }
378 var prefixElems []string
379 prefixElems, g = g.SplitFixedPrefix()
380 name := naming.Join(prefixElems...)
381 if len(root) != 0 {
382 name = naming.JoinAddressName(root, name)
383 }
Todd Wang702385a2014-11-07 01:54:08 -0800384 c := watch.GlobWatcherClient(name)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700385 for retry := false; ; retry = true {
386 if retry {
387 time.Sleep(10 * time.Second)
388 }
389 stream, err := c.WatchGlob(ctx, watchtypes.GlobRequest{Pattern: g.String()})
390 if err != nil {
391 errors <- fmt.Errorf("%s: %v", name, err)
392 continue
393 }
394 iterator := stream.RecvStream()
395 for iterator.Advance() {
396 v := iterator.Value()
397 results <- fmt.Sprintf("%s: %s", naming.Join(name, v.Name), formatValue(v.Value))
398 }
399 if err = iterator.Err(); err != nil {
400 errors <- fmt.Errorf("%s: %v", name, err)
401 continue
402 }
403 if err = stream.Finish(); err != nil {
404 errors <- fmt.Errorf("%s: %v", name, err)
405 }
Robin Thellend663bf482014-10-01 10:27:10 -0700406 }
Robin Thellend663bf482014-10-01 10:27:10 -0700407}
408
409func formatValue(value interface{}) string {
410 var buf bytes.Buffer
411 if showType {
412 fmt.Fprintf(&buf, "%T: ", value)
413 }
414 if raw {
Robin Thellend6e441752014-12-13 11:29:42 -0800415 if v, ok := value.(istats.HistogramValue); ok {
416 // Bypass HistogramValue.String()
417 type hist istats.HistogramValue
418 value = hist(v)
419 }
Robin Thellend663bf482014-10-01 10:27:10 -0700420 fmt.Fprintf(&buf, "%+v", value)
421 return buf.String()
422 }
Robin Thellend6e441752014-12-13 11:29:42 -0800423 fmt.Fprintf(&buf, "%v", value)
Robin Thellend663bf482014-10-01 10:27:10 -0700424 return buf.String()
425}
426
Robin Thellend663bf482014-10-01 10:27:10 -0700427var cmdPProfRun = &cmdline.Command{
428 Run: runPProf,
429 Name: "run",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700430 Short: "Runs the pprof tool.",
431 Long: "Runs the pprof tool.",
Robin Thellend663bf482014-10-01 10:27:10 -0700432 ArgsName: "<name> <profile> [passthru args] ...",
433 ArgsLong: `
434<name> is the name of the pprof object.
435<profile> the name of the profile to use.
436
437All the [passthru args] are passed to the pprof tool directly, e.g.
438
Robin Thellendfaa083a2014-10-22 13:41:18 -0700439$ debug pprof run a/b/c heap --text
Robin Thellend663bf482014-10-01 10:27:10 -0700440$ debug pprof run a/b/c profile -gv
441`,
442}
443
444func runPProf(cmd *cmdline.Command, args []string) error {
445 if min, got := 1, len(args); got < min {
446 return cmd.UsageErrorf("pprof: incorrect number of arguments, got %d, want >=%d", got, min)
447 }
448 name := args[0]
449 if len(args) == 1 {
450 return showPProfProfiles(cmd, name)
451 }
452 profile := args[1]
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800453 listener, err := client.StartProxy(gctx, name)
Robin Thellend663bf482014-10-01 10:27:10 -0700454 if err != nil {
455 return err
456 }
457 defer listener.Close()
458
459 // Construct the pprof command line:
460 // <pprofCmd> http://<proxyaddr>/pprof/<profile> [pprof flags]
461 pargs := []string{pprofCmd} // pprofCmd is purposely not escaped.
462 for i := 2; i < len(args); i++ {
463 pargs = append(pargs, shellEscape(args[i]))
464 }
465 pargs = append(pargs, shellEscape(fmt.Sprintf("http://%s/pprof/%s", listener.Addr(), profile)))
466 pcmd := strings.Join(pargs, " ")
467 fmt.Fprintf(cmd.Stdout(), "Running: %s\n", pcmd)
468 c := exec.Command("sh", "-c", pcmd)
469 c.Stdin = os.Stdin
470 c.Stdout = cmd.Stdout()
471 c.Stderr = cmd.Stderr()
472 return c.Run()
473}
474
475func showPProfProfiles(cmd *cmdline.Command, name string) error {
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800476 v, err := pprof.PProfClient(name).Profiles(gctx)
Robin Thellend663bf482014-10-01 10:27:10 -0700477 if err != nil {
478 return err
479 }
480 v = append(v, "profile")
481 sort.Strings(v)
482 fmt.Fprintln(cmd.Stdout(), "Available profiles:")
483 for _, p := range v {
484 fmt.Fprintf(cmd.Stdout(), " %s\n", p)
485 }
486 return nil
487}
488
489func shellEscape(s string) string {
490 if !strings.Contains(s, "'") {
491 return "'" + s + "'"
492 }
493 re := regexp.MustCompile("([\"$`\\\\])")
494 return `"` + re.ReplaceAllString(s, "\\$1") + `"`
495}
496
497var cmdPProfRunProxy = &cmdline.Command{
498 Run: runPProfProxy,
499 Name: "proxy",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700500 Short: "Runs an http proxy to a pprof object.",
501 Long: "Runs an http proxy to a pprof object.",
Robin Thellend663bf482014-10-01 10:27:10 -0700502 ArgsName: "<name>",
503 ArgsLong: `
504<name> is the name of the pprof object.
505`,
506}
507
508func runPProfProxy(cmd *cmdline.Command, args []string) error {
509 if want, got := 1, len(args); got != want {
510 return cmd.UsageErrorf("proxy: incorrect number of arguments, got %d, want %d", got, want)
511 }
512 name := args[0]
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800513 listener, err := client.StartProxy(gctx, name)
Robin Thellend663bf482014-10-01 10:27:10 -0700514 if err != nil {
515 return err
516 }
517 defer listener.Close()
518
519 fmt.Fprintln(cmd.Stdout())
520 fmt.Fprintf(cmd.Stdout(), "The pprof proxy is listening at http://%s/pprof\n", listener.Addr())
521 fmt.Fprintln(cmd.Stdout())
522 fmt.Fprintln(cmd.Stdout(), "Hit CTRL-C to exit")
523
Matt Rosencrantza5ad2722015-01-22 11:17:47 -0800524 <-signals.ShutdownOnSignals(gctx)
Robin Thellend663bf482014-10-01 10:27:10 -0700525 return nil
526}
527
528var cmdRoot = cmdline.Command{
529 Name: "debug",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700530 Short: "Command-line tool for interacting with the debug server.",
Robin Thellend663bf482014-10-01 10:27:10 -0700531 Long: "Command-line tool for interacting with the debug server.",
532 Children: []*cmdline.Command{
533 cmdGlob,
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -0800534 cmdVtrace,
Robin Thellend663bf482014-10-01 10:27:10 -0700535 &cmdline.Command{
536 Name: "logs",
537 Short: "Accesses log files",
538 Long: "Accesses log files",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700539 Children: []*cmdline.Command{cmdLogsRead, cmdLogsSize},
Robin Thellend663bf482014-10-01 10:27:10 -0700540 },
541 &cmdline.Command{
542 Name: "stats",
543 Short: "Accesses stats",
544 Long: "Accesses stats",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700545 Children: []*cmdline.Command{cmdStatsRead, cmdStatsWatch},
Robin Thellend663bf482014-10-01 10:27:10 -0700546 },
547 &cmdline.Command{
548 Name: "pprof",
549 Short: "Accesses profiling data",
550 Long: "Accesses profiling data",
551 Children: []*cmdline.Command{cmdPProfRun, cmdPProfRunProxy},
552 },
553 },
554}
555
Robin Thellend18205cf2014-10-21 13:53:59 -0700556func root() *cmdline.Command {
Robin Thellend663bf482014-10-01 10:27:10 -0700557 return &cmdRoot
558}