summaryrefslogtreecommitdiffhomepage
path: root/cmd
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2021-09-23 09:20:14 -0700
committerBrad Fitzpatrick <brad@danga.com>2021-09-23 10:01:14 -0700
commitefb84ca60de3cd87df4b66acf7faf8fd08af3907 (patch)
treebda9c007b61a714a50b8225aa8e61e7133ba5673 /cmd
parent27bc4e744ceaf54832581d5bbd3afb800ce50b42 (diff)
downloadtailscale-efb84ca60de3cd87df4b66acf7faf8fd08af3907.tar.xz
tailscale-efb84ca60de3cd87df4b66acf7faf8fd08af3907.zip
ipn/localapi, cmd/tailscale: add CPU & memory profile support, debug command
This was already possible on Linux if you ran tailscaled with --debug (which runs net/http/pprof), but it requires the user have the Go toolchain around. Also, it wasn't possible on macOS, as there's no way to run the IPNExtension with a debug server (it doesn't run tailscaled). And on Windows it's super tedious: beyond what users want to do or what we want to explain. Instead, put it in "tailscale debug" so it works and works the same on all platforms. Then we can ask users to run it when we're debugging something and they can email us the output files. Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/tailscale/cli/debug.go28
-rw-r--r--cmd/tailscaled/depaware.txt2
2 files changed, 29 insertions, 1 deletions
diff --git a/cmd/tailscale/cli/debug.go b/cmd/tailscale/cli/debug.go
index f5cc32ef6..2cb927841 100644
--- a/cmd/tailscale/cli/debug.go
+++ b/cmd/tailscale/cli/debug.go
@@ -36,6 +36,9 @@ var debugCmd = &ffcli.Command{
fs.BoolVar(&debugArgs.netMap, "netmap", true, "whether to include netmap in --ipn mode")
fs.BoolVar(&debugArgs.localCreds, "local-creds", false, "print how to connect to local tailscaled")
fs.StringVar(&debugArgs.file, "file", "", "get, delete:NAME, or NAME")
+ fs.StringVar(&debugArgs.cpuFile, "cpu-profile", "", "if non-empty, grab a CPU profile for --profile-sec seconds and write it to this file")
+ fs.StringVar(&debugArgs.memFile, "mem-profile", "", "if non-empty, grab a memory profile and write it to this file")
+ fs.IntVar(&debugArgs.cpuSec, "profile-seconds", 15, "number of seconds to run a CPU profile for, when --cpu-profile is non-empty")
return fs
})(),
}
@@ -49,6 +52,9 @@ var debugArgs struct {
file string
prefs bool
pretty bool
+ cpuSec int
+ cpuFile string
+ memFile string
}
func runDebug(ctx context.Context, args []string) error {
@@ -68,6 +74,28 @@ func runDebug(ctx context.Context, args []string) error {
fmt.Printf("curl --unix-socket %s http://foo/localapi/v0/status\n", paths.DefaultTailscaledSocket())
return nil
}
+ if out := debugArgs.cpuFile; out != "" {
+ log.Printf("Capturing CPU profile for %v seconds ...", debugArgs.cpuSec)
+ if v, err := tailscale.Profile(ctx, "profile", debugArgs.cpuSec); err != nil {
+ return err
+ } else {
+ if err := os.WriteFile(out, v, 0600); err != nil {
+ return err
+ }
+ log.Printf("CPU profile written to %s", out)
+ }
+ }
+ if out := debugArgs.memFile; out != "" {
+ log.Printf("Capturing memory profile ...")
+ if v, err := tailscale.Profile(ctx, "heap", 0); err != nil {
+ return err
+ } else {
+ if err := os.WriteFile(out, v, 0600); err != nil {
+ return err
+ }
+ log.Printf("Memory profile written to %s", out)
+ }
+ }
if debugArgs.prefs {
prefs, err := tailscale.GetPrefs(ctx)
if err != nil {
diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt
index c65a374fa..108e8e3a9 100644
--- a/cmd/tailscaled/depaware.txt
+++ b/cmd/tailscaled/depaware.txt
@@ -279,7 +279,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
net/http/httptrace from github.com/tcnksm/go-httpstat+
net/http/httputil from tailscale.com/ipn/localapi
net/http/internal from net/http+
- net/http/pprof from tailscale.com/cmd/tailscaled
+ net/http/pprof from tailscale.com/cmd/tailscaled+
net/textproto from golang.org/x/net/http/httpguts+
net/url from crypto/x509+
os from crypto/rand+