Ver Fonte

Fixed #TASK_QT-9810 [native-agent]支持jattach动态注入

Carl há 1 ano atrás
pai
commit
35e51f2c4e

+ 8 - 1
containers/stack.go → containers/apm_stack_dispatch.go

@@ -128,7 +128,14 @@ func (c *Container) jvmStackTrace(tracer *ebpftracer.Tracer, pid uint32) error {
 
 
 	p := c.processes[pid]
 	p := c.processes[pid]
 
 
-	p.uprobes = append(p.uprobes, tracer.AttachJVMStackUprobes("", c.Uprobes)...)
+	jvmStackProbes, err := tracer.AttachJVMStackUprobes(pid, c.AppInfo)
+
+	if err != nil {
+		klog.WithError(err).Errorf("[jvmStackTrace] Failed attach jvm stack.")
+		return err
+	}
+
+	p.uprobes = append(p.uprobes, jvmStackProbes...)
 	p.stackUprobesChecked = true
 	p.stackUprobesChecked = true
 
 
 	return nil
 	return nil

+ 3 - 0
containers/container_apm.go

@@ -536,8 +536,11 @@ func (c *Container) detachUprobes(pid uint32) {
 	if p := c.processes[pid]; p != nil {
 	if p := c.processes[pid]; p != nil {
 		if len(p.uprobes) > 0 {
 		if len(p.uprobes) > 0 {
 			klog.Infof("detachUprobes", pid)
 			klog.Infof("detachUprobes", pid)
+			// 关闭应用层uprobes
 			p.DynamicClose()
 			p.DynamicClose()
+			// 关闭7层监控
 			c.l7Attach = false
 			c.l7Attach = false
+			// 清空应用注册信息
 			c.AppInfo = AppInfo{}
 			c.AppInfo = AppInfo{}
 		}
 		}
 	}
 	}

+ 5 - 0
containers/process.go

@@ -87,6 +87,11 @@ func (p *Process) DynamicClose() {
 	p.goTlsUprobesChecked = false
 	p.goTlsUprobesChecked = false
 	p.openSslUprobesChecked = false
 	p.openSslUprobesChecked = false
 	p.jvmUprobesChecked = false
 	p.jvmUprobesChecked = false
+	// TODO 移除 tiny-agent
+	if p.codeType.IsJvmCode() && p.stackUprobesChecked {
+
+	}
+
 	p.stackUprobesChecked = false
 	p.stackUprobesChecked = false
 	p.uprobes = []link.Link{}
 	p.uprobes = []link.Link{}
 }
 }

+ 83 - 12
ebpftracer/stack.go

@@ -1,13 +1,22 @@
 package ebpftracer
 package ebpftracer
 
 
 import (
 import (
+	"bufio"
+	"fmt"
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/link"
 	"github.com/cilium/ebpf/link"
 	"github.com/coroot/coroot-node-agent/ebpftracer/tracer"
 	"github.com/coroot/coroot-node-agent/ebpftracer/tracer"
+	"github.com/coroot/coroot-node-agent/ebpftracer/tracer/jattach"
 	"github.com/coroot/coroot-node-agent/utils"
 	"github.com/coroot/coroot-node-agent/utils"
+	. "github.com/coroot/coroot-node-agent/utils/modelse"
 	klog "github.com/sirupsen/logrus"
 	klog "github.com/sirupsen/logrus"
+	"os"
+	"path/filepath"
+	"strings"
 )
 )
 
 
+// AttachStackUprobes
+// default process stack
 func (t *Tracer) AttachStackUprobes(path string, uprobes []tracer.Uprobe) []link.Link {
 func (t *Tracer) AttachStackUprobes(path string, uprobes []tracer.Uprobe) []link.Link {
 	var links []link.Link
 	var links []link.Link
 
 
@@ -39,29 +48,61 @@ func (t *Tracer) AttachStackUprobes(path string, uprobes []tracer.Uprobe) []link
 	return links
 	return links
 }
 }
 
 
-func (t *Tracer) AttachJVMStackUprobes(path string, uprobes []tracer.Uprobe) []link.Link {
-	// TODO copy至目标进程读取
-	//utils.GetDefaultAgentsPath("NativeAgent","libnativeAgent.so")
+// JVM process stack
+func (t *Tracer) AttachJVMStackUprobes(pid uint32, appInfo AppInfo) ([]link.Link, error) {
+	klog.Infoln("[Jvm stack uprobe] Attach Start AttachJVMStackUprobes", pid)
+	// TODO tiny Agent 注入
+	//argkv := "/opt/github/euspace/dist/package_dir/agents/NativeAgent/lib/apmAgent.jar=/opt/github/euspace/dist/package_dir/agents/NativeAgent"
+
+	nativeBasePath := utils.GetDefaultAgentsPath("NativeAgent")
+	kvPairs := []string{
+		fmt.Sprintf("%s=%s", filepath.Join(nativeBasePath, "lib", "apmAgent.jar"), nativeBasePath),
+		fmt.Sprintf("%s=%d", "appId", appInfo.AppIdHash.IntVal),
+		fmt.Sprintf("%s=%d", "agentId", appInfo.AgentId),
+		fmt.Sprintf("%s=%d", "hostId", utils.GetIntHostID()),
+		fmt.Sprintf("%s=%d", "accountId", utils.GetAccountID()),
+	}
+	argkv := strings.Join(kvPairs, ",")
+	klog.Infof("[Jvm stack uprobe] params:[%s]", argkv)
+
+	args := []string{"load", "instrument", "false", argkv}
+	jattacher := jattach.JvmJattacher{
+		Pid:         pid,
+		Args:        args,
+		PrintOutput: 1,
+	}
+
+	res, err := jattacher.JAttach()
+	klog.Infof("[Jvm stack uprobe] JAttach Result: %d", res)
+	if err != nil {
+		return nil, err
+	}
+
 	//path = utils.GetDefaultAgentsPath("NativeAgent", "libnativeAgent.so")
 	//path = utils.GetDefaultAgentsPath("NativeAgent", "libnativeAgent.so")
-	//path = "/tmp/NativeAgentSo2378900480034120722.tmp"
-	path = utils.GetDefaultAgentsPath("NativeAgent", "libnativeAgent.so")
+	//tmp/NativeAgentSo2297066477572820801.tmp
+	path, err := FindNativeSoFromMapped(pid, "NativeAgentSo", ".tmp")
+	if err != nil {
+		klog.Error(err)
+		return nil, err
+	}
 
 
 	setNodeEnter := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeEnter"
 	setNodeEnter := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeEnter"
 	setNodeReturn := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeReturn"
 	setNodeReturn := "Java_com_cloudwise_agent_common_natives_TraceNative_setNodeReturn"
 
 
-	klog.Infoln("Attach Start AttachJVMStackUprobes", path)
+	klog.Infoln("[Jvm stack uprobe] Attach Start AttachJVMStackUprobes", path)
 
 
 	var links []link.Link
 	var links []link.Link
 	ex, err := link.OpenExecutable(path)
 	ex, err := link.OpenExecutable(path)
 	if err != nil {
 	if err != nil {
 		klog.Error(err)
 		klog.Error(err)
-		return nil
+		return nil, err
 	}
 	}
 
 
-	klog.Infoln("Attach Start " + setNodeEnter)
-	uplink, err := ex.Uprobe(setNodeEnter, t.uprobes["setNodeEnter"], &link.UprobeOptions{Offset: 0x0})
+	klog.Infof("[Jvm stack uprobe] Attach Start [%s] [%s] ", setNodeEnter, setNodeReturn)
+	uplink, err := ex.Uprobe(setNodeEnter, t.uprobes["setNodeEnter"], &link.UprobeOptions{Offset: 0x0, PID: int(pid)})
 	if err != nil {
 	if err != nil {
-		klog.Errorf("attaching ERROR: %v, %v, %v\n", err, setNodeEnter, uplink)
+		klog.Errorf("[Jvm stack uprobe] Attaching ERROR: %v, %v, %v\n", err, setNodeEnter, uplink)
+		return nil, err
 	} else {
 	} else {
 		links = append(links, uplink)
 		links = append(links, uplink)
 	}
 	}
@@ -69,9 +110,39 @@ func (t *Tracer) AttachJVMStackUprobes(path string, uprobes []tracer.Uprobe) []l
 	klog.Infoln("Attach Start " + setNodeReturn)
 	klog.Infoln("Attach Start " + setNodeReturn)
 	uplink, err = ex.Uprobe(setNodeReturn, t.uprobes["setNodeReturn"], &link.UprobeOptions{Offset: 0x0})
 	uplink, err = ex.Uprobe(setNodeReturn, t.uprobes["setNodeReturn"], &link.UprobeOptions{Offset: 0x0})
 	if err != nil {
 	if err != nil {
-		klog.Errorf("attaching ERROR: %v, %v, %v\n", err, setNodeReturn, uplink)
+		klog.Errorf("[Jvm stack uprobe] Attaching ERROR: %v, %v, %v\n", err, setNodeReturn, uplink)
+		return nil, err
 	} else {
 	} else {
 		links = append(links, uplink)
 		links = append(links, uplink)
 	}
 	}
-	return links
+	return links, nil
+}
+
+func FindNativeSoFromMapped(pid uint32, prefix, suffix string) (string, error) {
+	// todo rootfs
+	mapsFile := fmt.Sprintf("/proc/%d/maps", pid)
+	tmpFile, err := os.Open(mapsFile)
+	if err != nil {
+		return "", fmt.Errorf("error opening maps file: %v", err)
+	}
+	defer tmpFile.Close()
+
+	// 使用 bufio.Scanner 逐行读取文件内容
+	scanner := bufio.NewScanner(tmpFile)
+	for scanner.Scan() {
+		line := scanner.Text()
+		// 检查路径部分是否包含 "NativeAgentSo" 且以 ".tmp" 结尾
+		if strings.Contains(line, prefix) && strings.HasSuffix(line, suffix) {
+			parts := strings.Fields(line)
+			if len(parts) > 5 {
+				return parts[len(parts)-1], nil // 返回路径
+			}
+		}
+	}
+
+	if err = scanner.Err(); err != nil {
+		return "", fmt.Errorf("error reading maps file: %v", err)
+	}
+
+	return "", fmt.Errorf("no matching path found")
 }
 }

+ 37 - 0
ebpftracer/tracer/jattach/jattach_linux_amd64.go

@@ -0,0 +1,37 @@
+package jattach
+
+/*
+#cgo CFLAGS: -I include
+#cgo amd64 LDFLAGS: ${SRCDIR}/lib/libjattach.a
+#cgo arm64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_arm64.a
+#include <stdlib.h>
+// declaration jattach
+int jattach(int pid, int argc, char** argv, int print_output);
+*/
+import "C"
+import (
+	"fmt"
+	"unsafe"
+)
+
+type JvmJattacher struct {
+	Pid         uint32
+	Args        []string
+	PrintOutput int
+}
+
+func (j *JvmJattacher) JAttach() (int, error) {
+	cArgs := make([]*C.char, len(j.Args))
+	for i, arg := range j.Args {
+		cArgs[i] = C.CString(arg)
+		defer C.free(unsafe.Pointer(cArgs[i])) // free mem
+	}
+
+	// call C func jattach
+	// cArgs to **C.char
+	result := C.jattach(C.int(j.Pid), C.int(len(j.Args)), (**C.char)(unsafe.Pointer(&cArgs[0])), C.int(j.PrintOutput))
+	if int(result) != 0 {
+		return int(result), fmt.Errorf("[JAttach] jattacher failed")
+	}
+	return int(result), nil
+}

BIN
ebpftracer/tracer/jattach/lib/libjattach.a


+ 5 - 0
utils/id.go

@@ -81,6 +81,11 @@ func GetHostID() (int64, HashByte) {
 	return id, charArray
 	return id, charArray
 }
 }
 
 
+func GetIntHostID() int64 {
+	id, _ := GetHostID()
+	return id
+}
+
 func MachineID() string {
 func MachineID() string {
 	for _, p := range []string{"sys/devices/virtual/dmi/id/product_uuid", "etc/machine-id", "var/lib/dbus/machine-id"} {
 	for _, p := range []string{"sys/devices/virtual/dmi/id/product_uuid", "etc/machine-id", "var/lib/dbus/machine-id"} {
 		payload, err := os.ReadFile(path.Join("/proc/1/root", p))
 		payload, err := os.ReadFile(path.Join("/proc/1/root", p))