Jelajahi Sumber

Feature #TASK_QT-18250 General nginx

Carl 1 bulan lalu
induk
melakukan
3f5b5dead4

+ 23 - 0
containers/container.go

@@ -1452,6 +1452,8 @@ func (c *Container) AttachUprobes(tracer *ebpftracer.Tracer, pid uint32, _type s
 		err = c.attachPythonUprobes(tracer, pid)
 	case CodeTypeNode:
 		err = c.attachNodejsUprobes(tracer, pid)
+	case CodeTypeNginx:
+		err = c.attachNginxUprobes(tracer, pid)
 	default:
 		klog.Warningf("[attach] Not Supported codeType: %s", codeType.String())
 		return fmt.Errorf("[attach] Not Supported codeType: %s", codeType.String())
@@ -1729,6 +1731,27 @@ func (c *Container) attachNodejsUprobes(tracer *ebpftracer.Tracer, pid uint32) e
 	return nil
 }
 
+func (c *Container) attachNginxUprobes(tracer *ebpftracer.Tracer, pid uint32) error {
+	if common.IsOpenFilter() && !common.IsFilterPid(pid) {
+		return nil
+	}
+	p := c.processes[pid]
+	if p == nil {
+		return nil
+	}
+	if !p.nginxAttachOnce {
+		p.nginxAttachOnce = true
+		err := tracer.InitKProcInfo(pid, &c.AppInfo)
+		if err != nil {
+			klog.Error(err)
+			return err
+		}
+		klog.Infof("[attach] nginx proc succeed! pid:[%d]", pid)
+		c.l7AttachSuccess()
+	}
+	return nil
+}
+
 func resolveFd(pid uint32, fd uint64) (mntId string, logPath string) {
 	info := proc.GetFdInfo(pid, fd)
 	if info == nil {

+ 1 - 0
containers/process.go

@@ -39,6 +39,7 @@ type Process struct {
 	jvmAttachOnce    bool
 	pyAttachOnce     bool
 	nodejsAttachOnce bool
+	nginxAttachOnce  bool
 	stackAttachOnce  bool
 	stackStatus      StackStatus
 	versionFailed    bool

+ 27 - 0
containers/util.go

@@ -52,6 +52,8 @@ func GetExeType(pid uint32, rootfs string) CodeType {
 		return CodeTypePython
 	} else if isNodeProcess(pid, rootfs) {
 		return CodeTypeNode
+	} else if isNginxProcess(pid, rootfs) {
+		return CodeTypeNginx
 	}
 	return CodeTypeUnknown
 }
@@ -324,6 +326,31 @@ func isNodeProcess(pid uint32, rootfs string) bool {
 	}
 }
 
+// isNginxProcess 判断进程是否为 nginx
+// 通过 /proc/<pid>/exe 的 readlink 和 cmdline 检查
+func isNginxProcess(pid uint32, rootfs string) bool {
+	// 1) 通过 exe 路径判断
+	exePath, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
+	if err != nil {
+		return false
+	}
+	base := filepath.Base(exePath)
+	if base == "nginx" {
+		return true
+	}
+
+	// 2) 通过 cmdline 判断(nginx worker 进程的 exe 可能是被 delete 的路径)
+	cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
+	if err != nil {
+		return false
+	}
+	lower := strings.ToLower(string(cmdline))
+	if strings.Contains(lower, "nginx") {
+		return true
+	}
+	return false
+}
+
 func getProcessPath(pid uint32) (string, error) {
 	switch runtime.GOOS {
 	case "linux":

+ 10 - 10
ebpftracer/ebpf/l7/l7.c

@@ -1987,7 +1987,7 @@ int tp_sched_wakeup(void *ctx)
 		return 0;
 
 	bpf_printk("\n");
-	bpf_printk("[sched_wakeup] [Start] waker=%u wakee=%u", waker_tid, wakee_tid);
+//	bpf_printk("[sched_wakeup] [Start] waker=%u wakee=%u", waker_tid, wakee_tid);
 
 	struct thread_ctx_t *wakee_ctx = bpf_map_lookup_elem(&thread_ctx, &wakee_tid);
 	struct thread_ctx_t *waker_ctx = bpf_map_lookup_elem(&thread_ctx, &waker_tid);
@@ -1995,8 +1995,8 @@ int tp_sched_wakeup(void *ctx)
 	// 🧠 新增逻辑:如果双方都存在且都为主线程,则跳过 update
 	if (wakee_ctx && waker_ctx &&
 	    wakee_ctx->is_main_thread == 1 && waker_ctx->is_main_thread == 1) {
-		bpf_printk("    [sched_wakeup] [skip update] both main threads (waker=%u wakee=%u)",
-		           waker_tid, wakee_tid);
+//		bpf_printk("    [sched_wakeup] [skip update] both main threads (waker=%u wakee=%u)",
+//		           waker_tid, wakee_tid);
 		return 0;
 	}
 
@@ -2033,12 +2033,12 @@ int tp_sched_wakeup(void *ctx)
 	else if (waker_ctx && waker_ctx->is_main_thread == 1)
 		trace_id = waker_ctx->token;
 
-	if (!wakee_ctx)
-		bpf_printk("    [sched_wakeup] [not find prev_ctx] wakee_tid(%u)", wakee_tid);
-	if (!waker_ctx)
-		bpf_printk("    [sched_wakeup] [waker_ctx] [not find prev_ctx] tid:%u", waker_tid);
-
-	bpf_printk("[sched_wakeup] [End] new edge: waker=%u -> wakee=%u trace_id=%llu",
-	           waker_tid, wakee_tid, trace_id);
+//	if (!wakee_ctx)
+//		bpf_printk("    [sched_wakeup] [not find prev_ctx] wakee_tid(%u)", wakee_tid);
+//	if (!waker_ctx)
+//		bpf_printk("    [sched_wakeup] [waker_ctx] [not find prev_ctx] tid:%u", waker_tid);
+//
+//	bpf_printk("[sched_wakeup] [End] new edge: waker=%u -> wakee=%u trace_id=%llu",
+//	           waker_tid, wakee_tid, trace_id);
 	return 0;
 }

+ 4 - 3
ebpftracer/ebpf/l7/sk_msg.c

@@ -218,12 +218,13 @@ int sk_msg_handler(struct sk_msg_md *msg)
 	}
 //	bpf_printk("HTTP request: %s",map_data->payload);
 
-	// header 查询
-	long header_start_native = 0x0a0d312e312f5054LL; // 小端序下的 "TP/1.1\r\n" (0x54 0x50 0x2f 0x31 0x2e 0x31 0x0d 0x0a)
+	// header 查询: 同时匹配 "TP/1.1\r\n" 和 "TP/1.0\r\n"
+	// '0'(0x30) 与 '1'(0x31) 仅差 bit0,OR 该位后统一比较
+	long header_match = 0x0a0d312e312f5054LL; // "TP/1.1\r\n" 小端序
 #pragma clang loop unroll(full)
 	for (__u32 i = 0; i < 200 - 8; i++) {
 		long data = *(long long *) (map_data->payload + i);
-		if (data == header_start_native) {
+		if ((data | (1LL << 40)) == header_match) {
 			map_data->header_offset_idx = i + 8;
 			break;
 		}

+ 2 - 0
utils/modelse/code_type.go

@@ -80,6 +80,8 @@ func (p CodeType) Topic() string {
 	//	return "DOTNET"
 	case CodeTypeNode:
 		return "nodeTopic"
+	case CodeTypeNginx:
+		return "nginxTopic"
 	//case CodeTypeC:
 	//	return "C"
 	//case CodeTypeNetCore: