diff --git a/cmd/tailscale/cli/debug.go b/cmd/tailscale/cli/debug.go index 2cb927841..1b12e28e0 100644 --- a/cmd/tailscale/cli/debug.go +++ b/cmd/tailscale/cli/debug.go @@ -36,8 +36,8 @@ 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.StringVar(&debugArgs.cpuFile, "cpu-profile", "", "if non-empty, grab a CPU profile for --profile-sec seconds and write it to this file; - for stdout") + fs.StringVar(&debugArgs.memFile, "mem-profile", "", "if non-empty, grab a memory profile and write it to this file; - for stdout") fs.IntVar(&debugArgs.cpuSec, "profile-seconds", 15, "number of seconds to run a CPU profile for, when --cpu-profile is non-empty") return fs })(), @@ -57,6 +57,24 @@ var debugArgs struct { memFile string } +func writeProfile(dst string, v []byte) error { + if dst == "-" { + _, err := os.Stdout.Write(v) + return err + } + return os.WriteFile(dst, v, 0600) +} + +func outName(dst string) string { + if dst == "-" { + return "stdout" + } + if runtime.GOOS == "darwin" { + return fmt.Sprintf("%s (warning: sandboxed macOS binaries write to Library/Containers; use - to write to stdout and redirect to file instead)", dst) + } + return dst +} + func runDebug(ctx context.Context, args []string) error { if len(args) > 0 { return errors.New("unknown arguments") @@ -79,10 +97,10 @@ func runDebug(ctx context.Context, args []string) error { if v, err := tailscale.Profile(ctx, "profile", debugArgs.cpuSec); err != nil { return err } else { - if err := os.WriteFile(out, v, 0600); err != nil { + if err := writeProfile(out, v); err != nil { return err } - log.Printf("CPU profile written to %s", out) + log.Printf("CPU profile written to %s", outName(out)) } } if out := debugArgs.memFile; out != "" { @@ -90,10 +108,10 @@ func runDebug(ctx context.Context, args []string) error { if v, err := tailscale.Profile(ctx, "heap", 0); err != nil { return err } else { - if err := os.WriteFile(out, v, 0600); err != nil { + if err := writeProfile(out, v); err != nil { return err } - log.Printf("Memory profile written to %s", out) + log.Printf("Memory profile written to %s", outName(out)) } } if debugArgs.prefs {