@@ -19,6 +19,7 @@ import (
1919 "github.com/pyroscope-io/pyroscope/pkg/agent/spy"
2020 "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/remote"
2121 "github.com/pyroscope-io/pyroscope/pkg/config"
22+ "github.com/pyroscope-io/pyroscope/pkg/util/atexit"
2223 "github.com/sirupsen/logrus"
2324)
2425
@@ -32,7 +33,7 @@ func Cli(cfg *config.Config, args []string) error {
3233 baseName := path .Base (args [0 ])
3334 spyName = spy .ResolveAutoName (baseName )
3435 if spyName == "" {
35- supportedSpies := supportedSpiesWithoutGospy ()
36+ supportedSpies := spy . SupportedExecSpies ()
3637 suggestedCommand := fmt .Sprintf ("pyroscope exec -spy-name %s %s" , supportedSpies [0 ], strings .Join (args , " " ))
3738 return fmt .Errorf (
3839 "could not automatically find a spy for program \" %s\" . Pass spy name via %s argument, for example: \n %s\n \n Available spies are: %s\n %s\n If you believe this is a mistake, please submit an issue at %s" ,
@@ -69,36 +70,42 @@ func Cli(cfg *config.Config, args []string) error {
6970 UpstreamThreads : cfg .Exec .UpstreamThreads ,
7071 UpstreamRequestTimeout : cfg .Exec .UpstreamRequestTimeout ,
7172 })
73+ defer u .Stop ()
7274
73- // TODO: make configurable?
75+ // TODO: improve this logic, basically we need a smart way of detecting that an app successfully loaded.
76+ // Maybe do this on some ticker (every 100 ms) with a timeout (20 s). Make this configurable too
7477 time .Sleep (5 * time .Second )
75- // TODO: add sample rate
78+ // TODO: add sample rate, make it configurable
7679 sess := agent .NewSession (u , cfg .Exec .ApplicationName , spyName , 100 , cmd .Process .Pid , cfg .Exec .DetectSubprocesses )
7780 sess .Start ()
7881 defer sess .Stop ()
7982
80- // TODO: very hacky, at some point we'll need to make wait work
81- // cmd.Wait()
82-
83- for {
84- time .Sleep (time .Second )
85- p , err := ps .FindProcess (cmd .Process .Pid )
86- if p == nil || err != nil {
87- break
88- }
89- }
83+ waitForProcessToExit (cmd )
9084 return nil
9185}
9286
93- func supportedSpiesWithoutGospy () []string {
94- supportedSpies := []string {}
95- for _ , s := range spy .SupportedSpies {
96- if s != "gospy" {
97- supportedSpies = append (supportedSpies , s )
87+ // TODO: very hacky, at some point we'll need to make `cmd.Wait()` work
88+ // Currently the issue is that on Linux it often thinks the process exited when it did not.
89+ func waitForProcessToExit (cmd * exec.Cmd ) {
90+ sigc := make (chan struct {})
91+
92+ atexit .Register (func () {
93+ sigc <- struct {}{}
94+ })
95+
96+ t := time .NewTicker (time .Second )
97+ for {
98+ select {
99+ case <- sigc :
100+ cmd .Process .Kill ()
101+ return
102+ case <- t .C :
103+ p , err := ps .FindProcess (cmd .Process .Pid )
104+ if p == nil || err != nil {
105+ return
106+ }
98107 }
99108 }
100-
101- return supportedSpies
102109}
103110
104111func performChecks (spyName string ) error {
@@ -113,7 +120,7 @@ func performChecks(spyName string) error {
113120 }
114121
115122 if ! stringsContains (spy .SupportedSpies , spyName ) {
116- supportedSpies := supportedSpiesWithoutGospy ()
123+ supportedSpies := spy . SupportedExecSpies ()
117124 return fmt .Errorf (
118125 "Spy \" %s\" is not supported. Available spies are: %s\n %s" ,
119126 color .BlueString (spyName ),
0 commit comments