process.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package containers
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "github.com/coroot/coroot-node-agent/ebpftracer/tracer/jattach"
  7. . "github.com/coroot/coroot-node-agent/utils/modelse"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/cilium/ebpf/link"
  13. "github.com/coroot/coroot-node-agent/ebpftracer"
  14. "github.com/coroot/coroot-node-agent/proc"
  15. "github.com/jpillora/backoff"
  16. "github.com/mdlayher/taskstats"
  17. )
  18. type Process struct {
  19. Pid uint32
  20. StartedAt time.Time
  21. netNsId string
  22. ctx context.Context
  23. cancelFunc context.CancelFunc
  24. dotNetMonitor *DotNetMonitor
  25. isGolangApp bool
  26. uprobes []link.Link
  27. stackUprobes []link.Link
  28. goTlsUprobesChecked bool
  29. openSslUprobesChecked bool
  30. jvmAttachOnce bool
  31. pyAttachOnce bool
  32. nodejsAttachOnce bool
  33. stackAttachOnce bool
  34. stackStatus StackStatus
  35. versionFailed bool
  36. codeType CodeType
  37. cmdline string
  38. pythonGilChecked bool
  39. }
  40. func NewProcess(pid uint32, stats *taskstats.Stats, tracer *ebpftracer.Tracer) *Process {
  41. p := &Process{Pid: pid, StartedAt: stats.BeginTime}
  42. p.ctx, p.cancelFunc = context.WithCancel(context.Background())
  43. //go p.instrument(tracer)
  44. return p
  45. }
  46. func (p *Process) NetNsId() string {
  47. if p.netNsId == "" {
  48. ns, err := proc.GetNetNs(p.Pid)
  49. if err != nil {
  50. return ""
  51. }
  52. p.netNsId = ns.UniqueId()
  53. _ = ns.Close()
  54. }
  55. return p.netNsId
  56. }
  57. func (p *Process) isHostNs() bool {
  58. return p.NetNsId() == hostNetNsId
  59. }
  60. func (p *Process) instrument(tracer *ebpftracer.Tracer) {
  61. b := backoff.Backoff{Factor: 2, Min: time.Second, Max: time.Minute}
  62. for {
  63. select {
  64. case <-p.ctx.Done():
  65. return
  66. default:
  67. dest, err := os.Readlink(proc.Path(p.Pid, "exe"))
  68. if err != nil {
  69. return
  70. }
  71. if dest != "/" {
  72. p.instrumentPython(tracer)
  73. if dotNetAppName, err := dotNetApp(p.Pid); err == nil {
  74. if dotNetAppName != "" {
  75. p.dotNetMonitor = NewDotNetMonitor(p.ctx, p.Pid, dotNetAppName)
  76. }
  77. }
  78. return
  79. }
  80. time.Sleep(b.Duration())
  81. }
  82. }
  83. }
  84. func (p *Process) instrumentPython(tracer *ebpftracer.Tracer) {
  85. if p.pythonGilChecked {
  86. return
  87. }
  88. p.pythonGilChecked = true
  89. cmdline := proc.GetCmdline(p.Pid)
  90. if len(cmdline) == 0 {
  91. return
  92. }
  93. parts := bytes.Split(cmdline, []byte{0})
  94. cmd := parts[0]
  95. if len(cmd) == 0 {
  96. return
  97. }
  98. cmd = bytes.TrimSuffix(bytes.Fields(cmd)[0], []byte{':'})
  99. if !pythonCmd.Match(cmd) {
  100. return
  101. }
  102. p.uprobes = append(p.uprobes, tracer.AttachPythonThreadLockProbes(p.Pid)...)
  103. }
  104. func (p *Process) Close() {
  105. p.cancelFunc()
  106. for _, u := range p.uprobes {
  107. _ = u.Close()
  108. }
  109. }
  110. func (p *Process) closeStackUprobes() error {
  111. for _, u := range p.stackUprobes {
  112. err := u.Close()
  113. if err != nil {
  114. return err
  115. }
  116. }
  117. p.stackUprobes = []link.Link{}
  118. p.stackStatus.StackUprobesClose()
  119. return nil
  120. }
  121. func (p *Process) DynamicClose(closeType int) {
  122. for _, u := range p.uprobes {
  123. _ = u.Close()
  124. }
  125. //p.goTlsUprobesChecked = false
  126. //p.openSslUprobesChecked = false
  127. //p.jvmUprobesChecked = false
  128. //if p.codeType.IsJvmCode() && p.stackUprobesChecked {
  129. // nativeBasePath := utils.GetDefaultAgentsPath("NativeAgent")
  130. // kvPairs := []string{
  131. // fmt.Sprintf("%s=%s", filepath.Join(nativeBasePath, "lib", "apmAgent.jar"), nativeBasePath),
  132. // "UNINSTALL",
  133. // }
  134. // argkv := strings.Join(kvPairs, ",")
  135. // args := []string{"load", "instrument", "false", argkv}
  136. // jattacher := jattach.JvmJattacher{
  137. // Pid: p.Pid,
  138. // Args: args,
  139. // PrintOutput: 1,
  140. // }
  141. // _, err := jattacher.JDetach()
  142. // if err == nil {
  143. // //p.stackUprobesChecked = false
  144. // }
  145. //}
  146. p.uprobes = []link.Link{}
  147. }
  148. func (p *Process) uninstallJavaAgent() error {
  149. if p.codeType.IsJvmCode() && p.stackAttachOnce {
  150. //nativeBasePath := utils.GetDefaultAgentsPath("NativeAgent")
  151. nativeBasePath := "/tmp/NativeAgent"
  152. kvPairs := []string{
  153. fmt.Sprintf("%s=%s", filepath.Join(nativeBasePath, "lib", "apmAgent.jar"), nativeBasePath),
  154. "UNINSTALL",
  155. }
  156. argkv := strings.Join(kvPairs, ",")
  157. args := []string{"load", "instrument", "false", argkv}
  158. jattacher := jattach.JvmJattacher{
  159. Pid: p.Pid,
  160. Args: args,
  161. PrintOutput: 1,
  162. }
  163. _, err := jattacher.JDetach()
  164. if err != nil {
  165. return err
  166. }
  167. p.stackStatus.JattachClose()
  168. return nil
  169. }
  170. return nil
  171. }
  172. func (p *Process) GetCmdline() string {
  173. return p.cmdline
  174. }