blob: a37355a2b31a8a8fa56e7532fcff58bf5696ec38 [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"
18 "v.io/core/veyron2/context"
19 "v.io/core/veyron2/naming"
20 "v.io/core/veyron2/services/mgmt/logreader"
21 logtypes "v.io/core/veyron2/services/mgmt/logreader/types"
22 "v.io/core/veyron2/services/mgmt/pprof"
23 "v.io/core/veyron2/services/mgmt/stats"
24 vtracesvc "v.io/core/veyron2/services/mgmt/vtrace"
25 "v.io/core/veyron2/services/watch"
26 watchtypes "v.io/core/veyron2/services/watch/types"
27 "v.io/core/veyron2/uniqueid"
28 "v.io/core/veyron2/vdl/vdlutil"
29 "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() {
Todd Wang34ed4c62014-11-26 15:15:52 -080044 vdlutil.Register(istats.HistogramValue{})
Robin Thellend663bf482014-10-01 10:27:10 -070045
46 // logs read flags
Robin Thellendfaa083a2014-10-22 13:41:18 -070047 cmdLogsRead.Flags.BoolVar(&follow, "f", false, "When true, read will wait for new log entries when it reaches the end of the file.")
48 cmdLogsRead.Flags.BoolVar(&verbose, "v", false, "When true, read will be more verbose.")
49 cmdLogsRead.Flags.IntVar(&numEntries, "n", int(logtypes.AllEntries), "The number of log entries to read.")
50 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 -070051
Robin Thellendfaa083a2014-10-22 13:41:18 -070052 // stats read flags
53 cmdStatsRead.Flags.BoolVar(&raw, "raw", false, "When true, the command will display the raw value of the object.")
54 cmdStatsRead.Flags.BoolVar(&showType, "type", false, "When true, the type of the values will be displayed.")
Robin Thellend663bf482014-10-01 10:27:10 -070055
Robin Thellendfaa083a2014-10-22 13:41:18 -070056 // stats watch flags
57 cmdStatsWatch.Flags.BoolVar(&raw, "raw", false, "When true, the command will display the raw value of the object.")
58 cmdStatsWatch.Flags.BoolVar(&showType, "type", false, "When true, the type of the values will be displayed.")
Robin Thellend663bf482014-10-01 10:27:10 -070059
60 // pprof flags
Jing Jin06d0dd62014-12-26 15:29:56 -080061 cmdPProfRun.Flags.StringVar(&pprofCmd, "pprofcmd", "v23 go tool pprof", "The pprof command to use.")
Robin Thellend663bf482014-10-01 10:27:10 -070062}
63
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -080064var cmdVtrace = &cmdline.Command{
65 Run: runVtrace,
66 Name: "vtrace",
67 Short: "Returns vtrace traces.",
68 Long: "Returns matching vtrace traces (or all stored traces if no ids are given).",
69 ArgsName: "<name> [id ...]",
70 ArgsLong: `
71<name> is the name of a vtrace object.
72[id] is a vtrace trace id.
73`,
74}
75
76func doFetchTrace(ctx context.T, wg *sync.WaitGroup, client vtracesvc.StoreClientStub,
77 id uniqueid.ID, traces chan *vtrace.TraceRecord, errors chan error) {
78 defer wg.Done()
79
80 trace, err := client.Trace(ctx, id)
81 if err != nil {
82 errors <- err
83 } else {
84 traces <- &trace
85 }
86}
87
88func runVtrace(cmd *cmdline.Command, args []string) error {
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -080089 ctx := runtime.NewContext()
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -080090 arglen := len(args)
91 if arglen == 0 {
92 return cmd.UsageErrorf("vtrace: incorrect number of arguments, got %d want >= 1", arglen)
93 }
94
95 name := args[0]
96 client := vtracesvc.StoreClient(name)
97 if arglen == 1 {
98 call, err := client.AllTraces(ctx)
99 if err != nil {
100 return err
101 }
102 stream := call.RecvStream()
103 for stream.Advance() {
104 trace := stream.Value()
105 vtrace.FormatTrace(os.Stdout, &trace, nil)
106 }
107 if err := stream.Err(); err != nil {
108 return err
109 }
110 return call.Finish()
111 }
112
113 ntraces := len(args) - 1
114 traces := make(chan *vtrace.TraceRecord, ntraces)
115 errors := make(chan error, ntraces)
116 var wg sync.WaitGroup
117 wg.Add(ntraces)
118 for _, arg := range args[1:] {
119 id, err := uniqueid.FromHexString(arg)
120 if err != nil {
121 return err
122 }
123 go doFetchTrace(ctx, &wg, client, id, traces, errors)
124 }
125 go func() {
126 wg.Wait()
127 close(traces)
128 close(errors)
129 }()
130
131 for trace := range traces {
132 vtrace.FormatTrace(os.Stdout, trace, nil)
133 }
134
135 // Just return one of the errors.
136 return <-errors
137}
138
Robin Thellend663bf482014-10-01 10:27:10 -0700139var cmdGlob = &cmdline.Command{
140 Run: runGlob,
141 Name: "glob",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700142 Short: "Returns all matching entries from the namespace.",
Robin Thellend663bf482014-10-01 10:27:10 -0700143 Long: "Returns all matching entries from the namespace.",
144 ArgsName: "<pattern> ...",
145 ArgsLong: `
146<pattern> is a glob pattern to match.
147`,
148}
149
150func runGlob(cmd *cmdline.Command, args []string) error {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700151 if min, got := 1, len(args); got < min {
152 return cmd.UsageErrorf("glob: incorrect number of arguments, got %d, want >=%d", got, min)
Robin Thellend663bf482014-10-01 10:27:10 -0700153 }
Robin Thellenda930f5a2014-10-07 09:54:25 -0700154 results := make(chan naming.MountEntry)
Robin Thellend663bf482014-10-01 10:27:10 -0700155 errors := make(chan error)
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800156 doGlobs(runtime.NewContext(), args, results, errors)
Robin Thellend663bf482014-10-01 10:27:10 -0700157 var lastErr error
Robin Thellend663bf482014-10-01 10:27:10 -0700158 for {
159 select {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700160 case err := <-errors:
161 lastErr = err
162 fmt.Fprintln(cmd.Stderr(), "Error:", err)
163 case me, ok := <-results:
164 if !ok {
165 return lastErr
166 }
167 fmt.Fprint(cmd.Stdout(), me.Name)
168 for _, s := range me.Servers {
David Why Use Two When One Will Do Presotto59a254c2014-10-30 13:09:29 -0700169 fmt.Fprintf(cmd.Stdout(), " %s (Expires %s)", s.Server, s.Expires)
Robin Thellend663bf482014-10-01 10:27:10 -0700170 }
171 fmt.Fprintln(cmd.Stdout())
Robin Thellend663bf482014-10-01 10:27:10 -0700172 }
173 }
Robin Thellend663bf482014-10-01 10:27:10 -0700174}
175
Robin Thellendfaa083a2014-10-22 13:41:18 -0700176// doGlobs calls Glob on multiple patterns in parallel and sends all the results
177// on the results channel and all the errors on the errors channel. It closes
178// the results channel when all the results have been sent.
179func doGlobs(ctx context.T, patterns []string, results chan<- naming.MountEntry, errors chan<- error) {
180 var wg sync.WaitGroup
181 wg.Add(len(patterns))
182 for _, p := range patterns {
183 go doGlob(ctx, p, results, errors, &wg)
184 }
185 go func() {
186 wg.Wait()
187 close(results)
188 }()
189}
190
191func doGlob(ctx context.T, pattern string, results chan<- naming.MountEntry, errors chan<- error, wg *sync.WaitGroup) {
192 defer wg.Done()
193 ctx, cancel := ctx.WithTimeout(time.Minute)
Robin Thellenda930f5a2014-10-07 09:54:25 -0700194 defer cancel()
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800195 c, err := runtime.Namespace().Glob(ctx, pattern)
Robin Thellend663bf482014-10-01 10:27:10 -0700196 if err != nil {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700197 errors <- fmt.Errorf("%s: %v", pattern, err)
Robin Thellend663bf482014-10-01 10:27:10 -0700198 return
199 }
Robin Thellendfaa083a2014-10-22 13:41:18 -0700200 for me := range c {
201 results <- me
Robin Thellend663bf482014-10-01 10:27:10 -0700202 }
Robin Thellend663bf482014-10-01 10:27:10 -0700203}
204
Robin Thellendfaa083a2014-10-22 13:41:18 -0700205var cmdLogsRead = &cmdline.Command{
206 Run: runLogsRead,
Robin Thellend663bf482014-10-01 10:27:10 -0700207 Name: "read",
208 Short: "Reads the content of a log file object.",
209 Long: "Reads the content of a log file object.",
210 ArgsName: "<name>",
211 ArgsLong: `
212<name> is the name of the log file object.
213`,
214}
215
Robin Thellendfaa083a2014-10-22 13:41:18 -0700216func runLogsRead(cmd *cmdline.Command, args []string) error {
Robin Thellend663bf482014-10-01 10:27:10 -0700217 if want, got := 1, len(args); want != got {
218 return cmd.UsageErrorf("read: incorrect number of arguments, got %d, want %d", got, want)
219 }
220 name := args[0]
Todd Wang702385a2014-11-07 01:54:08 -0800221 lf := logreader.LogFileClient(name)
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800222 stream, err := lf.ReadLog(runtime.NewContext(), startPos, int32(numEntries), follow)
Robin Thellend663bf482014-10-01 10:27:10 -0700223 if err != nil {
224 return err
225 }
226 iterator := stream.RecvStream()
227 for iterator.Advance() {
228 entry := iterator.Value()
229 if verbose {
230 fmt.Fprintf(cmd.Stdout(), "[%d] %s\n", entry.Position, entry.Line)
231 } else {
232 fmt.Fprintf(cmd.Stdout(), "%s\n", entry.Line)
233 }
234 }
235 if err = iterator.Err(); err != nil {
236 return err
237 }
238 offset, err := stream.Finish()
239 if err != nil {
240 return err
241 }
242 if verbose {
243 fmt.Fprintf(cmd.Stdout(), "Offset: %d\n", offset)
244 }
245 return nil
246}
247
Robin Thellendfaa083a2014-10-22 13:41:18 -0700248var cmdLogsSize = &cmdline.Command{
249 Run: runLogsSize,
Robin Thellend663bf482014-10-01 10:27:10 -0700250 Name: "size",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700251 Short: "Returns the size of a log file object.",
252 Long: "Returns the size of a log file object.",
Robin Thellend663bf482014-10-01 10:27:10 -0700253 ArgsName: "<name>",
254 ArgsLong: `
255<name> is the name of the log file object.
256`,
257}
258
Robin Thellendfaa083a2014-10-22 13:41:18 -0700259func runLogsSize(cmd *cmdline.Command, args []string) error {
Robin Thellend663bf482014-10-01 10:27:10 -0700260 if want, got := 1, len(args); want != got {
261 return cmd.UsageErrorf("size: incorrect number of arguments, got %d, want %d", got, want)
262 }
263 name := args[0]
Todd Wang702385a2014-11-07 01:54:08 -0800264 lf := logreader.LogFileClient(name)
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800265 size, err := lf.Size(runtime.NewContext())
Robin Thellend663bf482014-10-01 10:27:10 -0700266 if err != nil {
267 return err
268 }
269 fmt.Fprintln(cmd.Stdout(), size)
270 return nil
271}
272
Robin Thellendfaa083a2014-10-22 13:41:18 -0700273var cmdStatsRead = &cmdline.Command{
274 Run: runStatsRead,
275 Name: "read",
276 Short: "Returns the value of stats objects.",
277 Long: "Returns the value of stats objects.",
278 ArgsName: "<name> ...",
Robin Thellend663bf482014-10-01 10:27:10 -0700279 ArgsLong: `
Robin Thellendfaa083a2014-10-22 13:41:18 -0700280<name> is the name of a stats object, or a glob pattern to match against stats
281object names.
Robin Thellend663bf482014-10-01 10:27:10 -0700282`,
283}
284
Robin Thellendfaa083a2014-10-22 13:41:18 -0700285func runStatsRead(cmd *cmdline.Command, args []string) error {
286 if min, got := 1, len(args); got < min {
287 return cmd.UsageErrorf("read: incorrect number of arguments, got %d, want >=%d", got, min)
Robin Thellend663bf482014-10-01 10:27:10 -0700288 }
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800289 ctx := runtime.NewContext()
Robin Thellendfaa083a2014-10-22 13:41:18 -0700290 globResults := make(chan naming.MountEntry)
291 errors := make(chan error)
292 doGlobs(ctx, args, globResults, errors)
293
294 output := make(chan string)
295 go func() {
296 var wg sync.WaitGroup
297 for me := range globResults {
298 wg.Add(1)
299 go doValue(ctx, me.Name, output, errors, &wg)
300 }
301 wg.Wait()
302 close(output)
303 }()
304
305 var lastErr error
306 for {
307 select {
308 case err := <-errors:
309 lastErr = err
310 fmt.Fprintln(cmd.Stderr(), err)
311 case out, ok := <-output:
312 if !ok {
313 return lastErr
314 }
315 fmt.Fprintln(cmd.Stdout(), out)
316 }
Robin Thellend663bf482014-10-01 10:27:10 -0700317 }
Robin Thellend663bf482014-10-01 10:27:10 -0700318}
319
Robin Thellendfaa083a2014-10-22 13:41:18 -0700320func doValue(ctx context.T, name string, output chan<- string, errors chan<- error, wg *sync.WaitGroup) {
321 defer wg.Done()
Robin Thellendfaa083a2014-10-22 13:41:18 -0700322 ctx, cancel := ctx.WithTimeout(time.Minute)
323 defer cancel()
Todd Wang702385a2014-11-07 01:54:08 -0800324 v, err := stats.StatsClient(name).Value(ctx)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700325 if err != nil {
326 errors <- fmt.Errorf("%s: %v", name, err)
327 return
328 }
329 output <- fmt.Sprintf("%s: %v", name, formatValue(v))
330}
331
332var cmdStatsWatch = &cmdline.Command{
333 Run: runStatsWatch,
334 Name: "watch",
335 Short: "Returns a stream of all matching entries and their values as they change.",
336 Long: "Returns a stream of all matching entries and their values as they change.",
Robin Thellend663bf482014-10-01 10:27:10 -0700337 ArgsName: "<pattern> ...",
338 ArgsLong: `
339<pattern> is a glob pattern to match.
340`,
341}
342
Robin Thellendfaa083a2014-10-22 13:41:18 -0700343func runStatsWatch(cmd *cmdline.Command, args []string) error {
Robin Thellend663bf482014-10-01 10:27:10 -0700344 if want, got := 1, len(args); got < want {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700345 return cmd.UsageErrorf("watch: incorrect number of arguments, got %d, want >=%d", got, want)
Robin Thellend663bf482014-10-01 10:27:10 -0700346 }
347
348 results := make(chan string)
349 errors := make(chan error)
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800350 ctx := runtime.NewContext()
Robin Thellendfaa083a2014-10-22 13:41:18 -0700351 var wg sync.WaitGroup
352 wg.Add(len(args))
353 for _, arg := range args {
354 go doWatch(ctx, arg, results, errors, &wg)
Robin Thellend663bf482014-10-01 10:27:10 -0700355 }
Robin Thellendfaa083a2014-10-22 13:41:18 -0700356 go func() {
357 wg.Wait()
358 close(results)
359 }()
Robin Thellend663bf482014-10-01 10:27:10 -0700360 var lastErr error
Robin Thellend663bf482014-10-01 10:27:10 -0700361 for {
362 select {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700363 case err := <-errors:
364 lastErr = err
365 fmt.Fprintln(cmd.Stderr(), "Error:", err)
366 case r, ok := <-results:
367 if !ok {
368 return lastErr
369 }
Robin Thellend663bf482014-10-01 10:27:10 -0700370 fmt.Fprintln(cmd.Stdout(), r)
Robin Thellend663bf482014-10-01 10:27:10 -0700371 }
372 }
Robin Thellend663bf482014-10-01 10:27:10 -0700373}
374
Robin Thellendfaa083a2014-10-22 13:41:18 -0700375func doWatch(ctx context.T, pattern string, results chan<- string, errors chan<- error, wg *sync.WaitGroup) {
376 defer wg.Done()
Robin Thellend663bf482014-10-01 10:27:10 -0700377 root, globPattern := naming.SplitAddressName(pattern)
378 g, err := glob.Parse(globPattern)
379 if err != nil {
Robin Thellendfaa083a2014-10-22 13:41:18 -0700380 errors <- fmt.Errorf("%s: %v", globPattern, err)
Robin Thellend663bf482014-10-01 10:27:10 -0700381 return
382 }
383 var prefixElems []string
384 prefixElems, g = g.SplitFixedPrefix()
385 name := naming.Join(prefixElems...)
386 if len(root) != 0 {
387 name = naming.JoinAddressName(root, name)
388 }
Todd Wang702385a2014-11-07 01:54:08 -0800389 c := watch.GlobWatcherClient(name)
Robin Thellendfaa083a2014-10-22 13:41:18 -0700390 for retry := false; ; retry = true {
391 if retry {
392 time.Sleep(10 * time.Second)
393 }
394 stream, err := c.WatchGlob(ctx, watchtypes.GlobRequest{Pattern: g.String()})
395 if err != nil {
396 errors <- fmt.Errorf("%s: %v", name, err)
397 continue
398 }
399 iterator := stream.RecvStream()
400 for iterator.Advance() {
401 v := iterator.Value()
402 results <- fmt.Sprintf("%s: %s", naming.Join(name, v.Name), formatValue(v.Value))
403 }
404 if err = iterator.Err(); err != nil {
405 errors <- fmt.Errorf("%s: %v", name, err)
406 continue
407 }
408 if err = stream.Finish(); err != nil {
409 errors <- fmt.Errorf("%s: %v", name, err)
410 }
Robin Thellend663bf482014-10-01 10:27:10 -0700411 }
Robin Thellend663bf482014-10-01 10:27:10 -0700412}
413
414func formatValue(value interface{}) string {
415 var buf bytes.Buffer
416 if showType {
417 fmt.Fprintf(&buf, "%T: ", value)
418 }
419 if raw {
Robin Thellend6e441752014-12-13 11:29:42 -0800420 if v, ok := value.(istats.HistogramValue); ok {
421 // Bypass HistogramValue.String()
422 type hist istats.HistogramValue
423 value = hist(v)
424 }
Robin Thellend663bf482014-10-01 10:27:10 -0700425 fmt.Fprintf(&buf, "%+v", value)
426 return buf.String()
427 }
Robin Thellend6e441752014-12-13 11:29:42 -0800428 fmt.Fprintf(&buf, "%v", value)
Robin Thellend663bf482014-10-01 10:27:10 -0700429 return buf.String()
430}
431
Robin Thellend663bf482014-10-01 10:27:10 -0700432var cmdPProfRun = &cmdline.Command{
433 Run: runPProf,
434 Name: "run",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700435 Short: "Runs the pprof tool.",
436 Long: "Runs the pprof tool.",
Robin Thellend663bf482014-10-01 10:27:10 -0700437 ArgsName: "<name> <profile> [passthru args] ...",
438 ArgsLong: `
439<name> is the name of the pprof object.
440<profile> the name of the profile to use.
441
442All the [passthru args] are passed to the pprof tool directly, e.g.
443
Robin Thellendfaa083a2014-10-22 13:41:18 -0700444$ debug pprof run a/b/c heap --text
Robin Thellend663bf482014-10-01 10:27:10 -0700445$ debug pprof run a/b/c profile -gv
446`,
447}
448
449func runPProf(cmd *cmdline.Command, args []string) error {
450 if min, got := 1, len(args); got < min {
451 return cmd.UsageErrorf("pprof: incorrect number of arguments, got %d, want >=%d", got, min)
452 }
453 name := args[0]
454 if len(args) == 1 {
455 return showPProfProfiles(cmd, name)
456 }
457 profile := args[1]
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800458 listener, err := client.StartProxy(runtime, name)
Robin Thellend663bf482014-10-01 10:27:10 -0700459 if err != nil {
460 return err
461 }
462 defer listener.Close()
463
464 // Construct the pprof command line:
465 // <pprofCmd> http://<proxyaddr>/pprof/<profile> [pprof flags]
466 pargs := []string{pprofCmd} // pprofCmd is purposely not escaped.
467 for i := 2; i < len(args); i++ {
468 pargs = append(pargs, shellEscape(args[i]))
469 }
470 pargs = append(pargs, shellEscape(fmt.Sprintf("http://%s/pprof/%s", listener.Addr(), profile)))
471 pcmd := strings.Join(pargs, " ")
472 fmt.Fprintf(cmd.Stdout(), "Running: %s\n", pcmd)
473 c := exec.Command("sh", "-c", pcmd)
474 c.Stdin = os.Stdin
475 c.Stdout = cmd.Stdout()
476 c.Stderr = cmd.Stderr()
477 return c.Run()
478}
479
480func showPProfProfiles(cmd *cmdline.Command, name string) error {
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800481 v, err := pprof.PProfClient(name).Profiles(runtime.NewContext())
Robin Thellend663bf482014-10-01 10:27:10 -0700482 if err != nil {
483 return err
484 }
485 v = append(v, "profile")
486 sort.Strings(v)
487 fmt.Fprintln(cmd.Stdout(), "Available profiles:")
488 for _, p := range v {
489 fmt.Fprintf(cmd.Stdout(), " %s\n", p)
490 }
491 return nil
492}
493
494func shellEscape(s string) string {
495 if !strings.Contains(s, "'") {
496 return "'" + s + "'"
497 }
498 re := regexp.MustCompile("([\"$`\\\\])")
499 return `"` + re.ReplaceAllString(s, "\\$1") + `"`
500}
501
502var cmdPProfRunProxy = &cmdline.Command{
503 Run: runPProfProxy,
504 Name: "proxy",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700505 Short: "Runs an http proxy to a pprof object.",
506 Long: "Runs an http proxy to a pprof object.",
Robin Thellend663bf482014-10-01 10:27:10 -0700507 ArgsName: "<name>",
508 ArgsLong: `
509<name> is the name of the pprof object.
510`,
511}
512
513func runPProfProxy(cmd *cmdline.Command, args []string) error {
514 if want, got := 1, len(args); got != want {
515 return cmd.UsageErrorf("proxy: incorrect number of arguments, got %d, want %d", got, want)
516 }
517 name := args[0]
Matt Rosencrantz03f4b1d2014-11-24 11:01:17 -0800518 listener, err := client.StartProxy(runtime, name)
Robin Thellend663bf482014-10-01 10:27:10 -0700519 if err != nil {
520 return err
521 }
522 defer listener.Close()
523
524 fmt.Fprintln(cmd.Stdout())
525 fmt.Fprintf(cmd.Stdout(), "The pprof proxy is listening at http://%s/pprof\n", listener.Addr())
526 fmt.Fprintln(cmd.Stdout())
527 fmt.Fprintln(cmd.Stdout(), "Hit CTRL-C to exit")
528
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -0800529 <-signals.ShutdownOnSignals(runtime)
Robin Thellend663bf482014-10-01 10:27:10 -0700530 return nil
531}
532
533var cmdRoot = cmdline.Command{
534 Name: "debug",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700535 Short: "Command-line tool for interacting with the debug server.",
Robin Thellend663bf482014-10-01 10:27:10 -0700536 Long: "Command-line tool for interacting with the debug server.",
537 Children: []*cmdline.Command{
538 cmdGlob,
Matt Rosencrantzbe1a8b52014-11-21 15:14:06 -0800539 cmdVtrace,
Robin Thellend663bf482014-10-01 10:27:10 -0700540 &cmdline.Command{
541 Name: "logs",
542 Short: "Accesses log files",
543 Long: "Accesses log files",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700544 Children: []*cmdline.Command{cmdLogsRead, cmdLogsSize},
Robin Thellend663bf482014-10-01 10:27:10 -0700545 },
546 &cmdline.Command{
547 Name: "stats",
548 Short: "Accesses stats",
549 Long: "Accesses stats",
Robin Thellendfaa083a2014-10-22 13:41:18 -0700550 Children: []*cmdline.Command{cmdStatsRead, cmdStatsWatch},
Robin Thellend663bf482014-10-01 10:27:10 -0700551 },
552 &cmdline.Command{
553 Name: "pprof",
554 Short: "Accesses profiling data",
555 Long: "Accesses profiling data",
556 Children: []*cmdline.Command{cmdPProfRun, cmdPProfRunProxy},
557 },
558 },
559}
560
Robin Thellend18205cf2014-10-21 13:53:59 -0700561func root() *cmdline.Command {
Robin Thellend663bf482014-10-01 10:27:10 -0700562 return &cmdRoot
563}