process.go 4.4 KB

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