github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/agent/target/service.go (about) 1 package target 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/mitchellh/go-ps" 10 "github.com/pyroscope-io/pyroscope/pkg/agent" 11 "github.com/pyroscope-io/pyroscope/pkg/agent/spy" 12 "github.com/pyroscope-io/pyroscope/pkg/agent/upstream/remote" 13 "github.com/pyroscope-io/pyroscope/pkg/config" 14 "github.com/sirupsen/logrus" 15 ) 16 17 var ( 18 ErrNotFound = errors.New("service is not found") 19 ErrNotRunning = errors.New("service is not running") 20 ) 21 22 type service struct { 23 logger *logrus.Logger 24 target config.Target 25 sc agent.SessionConfig 26 } 27 28 func newServiceTarget(logger *logrus.Logger, upstream *remote.Remote, t config.Target) *service { 29 return &service{ 30 logger: logger, 31 target: t, 32 sc: agent.SessionConfig{ 33 Upstream: upstream, 34 AppName: t.ApplicationName, 35 Tags: t.Tags, 36 // TODO(kolesnikovae): target config should support specifying profile types. 37 ProfilingTypes: []spy.ProfileType{spy.ProfileCPU}, 38 SpyName: t.SpyName, 39 SampleRate: uint32(t.SampleRate), 40 UploadRate: 10 * time.Second, 41 WithSubprocesses: t.DetectSubprocesses, 42 Logger: logger, 43 // PID to be specified. 44 }, 45 } 46 } 47 48 func (s *service) attach(ctx context.Context) { 49 logger := s.logger.WithFields(logrus.Fields{ 50 "service-name": s.target.ServiceName, 51 "app-name": s.sc.AppName, 52 "spy-name": s.sc.SpyName}) 53 pid, err := getPID(s.target.ServiceName) 54 if err == nil { 55 logger.WithField("pid", pid).Debug("starting session") 56 s.sc.Pid = pid 57 err = s.wait(ctx) 58 } 59 if err != nil { 60 logger.WithError(err).Error("failed to attach spy to service") 61 } else { 62 logger.Debug("session ended") 63 } 64 } 65 66 func (s *service) wait(ctx context.Context) error { 67 session, err := agent.NewSession(s.sc) 68 if err != nil { 69 return err 70 } 71 if err := session.Start(); err != nil { 72 return err 73 } 74 defer session.Stop() 75 76 t := time.NewTicker(time.Second) 77 defer t.Stop() 78 for { 79 select { 80 case <-ctx.Done(): 81 return nil 82 case <-t.C: 83 p, err := ps.FindProcess(s.sc.Pid) 84 if err != nil { 85 return fmt.Errorf("could not find process: %w", err) 86 } 87 if p == nil && err == nil { 88 return nil 89 } 90 } 91 } 92 }