Parcourir la source

Feature #TASK_QT-31498 增加Parent Header解析,sys,service

Carl il y a 5 mois
Parent
commit
55cfa0d032

+ 12 - 0
ebpftracer/ebpf/include/apm_trace.h

@@ -36,6 +36,17 @@
 //#define CW_STREAM_HEADER_LEN 135 // CW_HEADER_KEY_LENGTH + 2 + CW_HEADER_VAL_LENGTH + 2 + 1
 #define CW_STREAM_HEADER_LEN (CW_HEADER_KEY_LENGTH + 2 + CW_HEADER_VAL_LENGTH + 2 + 1)
 
+// cwother
+// 格式:NN:ParentServiceName:MM[:ParentServiceSysTag]
+// NN: 2位数字(ASCII),表示 ParentServiceName 的长度(0-32)
+// MM: 2位数字(ASCII),表示 ParentServiceSysTag 的长度(0-32)
+// 当 MM=00 时,格式为 NN:ParentServiceName:00(不包含最后的冒号和SysTag)
+#define CW_SYS_HEADER_KEY_LENGTH 7
+#define CW_SYS_HEADER_KEY_VAL "cwother"
+#define CW_SYS_HEADER_KEY_UFIRST_VAL "Cwother"
+#define CW_SYS_LEN_PREFIX_LENGTH 2  // 每个长度字段的长度(NN 或 MM)
+#define CW_SYS_HEADER_VAL_LENGTH 76
+
 #define MAX_MQ_TOPIC_SIZE 256  // Max MQ topic size (e.g., Kafka topic)
 #define MAX_MQ_KEY_SIZE 256     // Max MQ key size (e.g., Kafka message key)
 
@@ -82,6 +93,7 @@ struct apm_span_context {
 	unsigned char trace_id[APM_TRACE_ID_SIZE];
 	unsigned char assumed_app_id[APM_ASSUMED_APP_ID_SIZE];
 	unsigned char span_id[APM_SPAN_ID_SIZE];
+	unsigned char sysvs[CW_SYS_HEADER_VAL_LENGTH];
 };
 
 // MQ 信息结构体(用于 Kafka、RabbitMQ 等消息队列)

+ 2 - 0
ebpftracer/ebpf/include/socket_trace_common.h

@@ -231,6 +231,8 @@ struct ebpf_proc_info {
 	// net.TCPAddr offsets
 	__u64 tcp_addr_ip_offset;    // net.TCPAddr.IP field offset
 	__u64 tcp_addr_port_offset;  // net.TCPAddr.Port field offset
+	// cwother header value: {app_name_len}:app_name:{SysTagLen}[:SysTag]
+	unsigned char sysvc[CW_SYS_HEADER_VAL_LENGTH];  // CW_SYS_HEADER_VAL_LENGTH
 } __attribute__((packed));
 
 enum {

+ 3 - 0
ebpftracer/ebpf/l7/l7.c

@@ -99,6 +99,7 @@ struct l7_event {
 	unsigned char app_id_from[APM_APP_ID_SIZE];
 	unsigned char span_id_from[APM_SPAN_ID_SIZE];
     unsigned char type_from[APM_TYPE_FROM_SIZE];
+    unsigned char sysvc_from[76];  // cwother header value: NN:ParentServiceName:MM:ParentServiceSysTag (CW_SYS_HEADER_VAL_LENGTH)
     unsigned char target_addr[64];
 
     // 错误消息字段
@@ -447,6 +448,8 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size,
 		    cw_copy_byte_arrays(cw_psc->app_id, e->app_id_from, APM_APP_ID_SIZE);
 		    cw_copy_byte_arrays(cw_psc->span_id, e->span_id_from, APM_SPAN_ID_SIZE);
             cw_copy_byte_arrays(cw_psc->type_from, e->type_from, APM_TYPE_FROM_SIZE);
+            cw_copy_byte_arrays(cw_psc->sysvs, e->sysvc_from, CW_SYS_HEADER_VAL_LENGTH);
+		    bpf_printk("trace_end %s",cw_psc->sysvs);
 		    // for (int i = 0; i < APM_TYPE_FROM_SIZE; i++) {
 			//     bpf_printk("trace_enter_write - type_from = %02x", e->type_from[i]);
 		    // }

+ 43 - 0
ebpftracer/ebpf/utrace/go/net/client.probe.bpf.c

@@ -62,6 +62,11 @@ struct cw_header_storage {
 	char end[2];
 };
 
+struct cw_sys_header_storage {
+	char sys_val[CW_SYS_HEADER_VAL_LENGTH];
+	char sys_str[CW_SYS_HEADER_KEY_LENGTH + 2 + CW_SYS_HEADER_VAL_LENGTH + 2];
+};
+
 struct {
 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
 	__uint(key_size, sizeof(u32));
@@ -69,6 +74,13 @@ struct {
 	__uint(max_entries, 1);
 } cw_header_storage_map SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+	__uint(key_size, sizeof(u32));
+	__uint(value_size, sizeof(struct cw_sys_header_storage));
+	__uint(max_entries, 1);
+} cw_sys_header_storage_map SEC(".maps");
+
 //struct {
 //	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
 //} events SEC(".maps");
@@ -633,6 +645,37 @@ int uprobe_writeSubset(struct pt_regs *ctx) {
 					goto done;
 				}
 			}
+			
+			// 插入 cwother header
+			// 直接从 proc_info->sysvc 获取值
+			u32 sys_map_id = 0;
+			struct cw_sys_header_storage *sys_storage = bpf_map_lookup_elem(&cw_sys_header_storage_map, &sys_map_id);
+			if (sys_storage) {
+				__builtin_memset(sys_storage, 0, sizeof(struct cw_sys_header_storage));
+				
+				// 从 proc_info->sysvc 读取值
+				// sysvc 格式:{app_name_len}:app_name:{SysTagLen}[:SysTag]
+				// 例如:08:eBPF-APP:00 或 08:eBPF-APP:03:tag
+				bpf_probe_read(sys_storage->sys_val, sizeof(sys_storage->sys_val), proc_info->sysvc);
+				
+				// 检查 sysvc 是否有值(第一个字符不是 '\0')
+				if (sys_storage->sys_val[0] != '\0' && len < (size - CW_SYS_HEADER_VAL_LENGTH - CW_SYS_HEADER_KEY_LENGTH - 4)) {
+					// Initialize sys_str with "cwother: "
+					__builtin_memcpy(sys_storage->sys_str, "cwother: ", CW_SYS_HEADER_KEY_LENGTH + 2);
+					__builtin_memcpy(&sys_storage->sys_str[CW_SYS_HEADER_KEY_LENGTH + 2], sys_storage->sys_val, sizeof(sys_storage->sys_val));
+					__builtin_memcpy(&sys_storage->sys_str[CW_SYS_HEADER_KEY_LENGTH + 2 + CW_SYS_HEADER_VAL_LENGTH], "\r\n", 2);
+					
+					if (bpf_probe_write_user(buf_ptr + (len & 0x0ffff), sys_storage->sys_str, sizeof(sys_storage->sys_str))) {
+						cw_bpf_debug("uprobe_writeSubset: Failed to write cwother header in buffer");
+						goto done;
+					}
+					len += CW_SYS_HEADER_KEY_LENGTH + 2 + CW_SYS_HEADER_VAL_LENGTH + 2;
+					if (bpf_probe_write_user((void *) (io_writer_ptr + proc_info->io_writer_n_pos), &len, sizeof(len))) {
+						cw_bpf_debug("uprobe_writeSubset: Failed to change io writer n for cwother");
+						goto done;
+					}
+				}
+			}
 		}
 	}
 	done:

+ 33 - 339
ebpftracer/ebpf/utrace/go/net/server.probe.bpf.c

@@ -110,6 +110,13 @@ struct {
 	__uint(max_entries, MAX_CONCURRENT);
 } http_server_context_headers SEC(".maps");
 
+struct {
+	__uint(type, BPF_MAP_TYPE_LRU_HASH);
+	__uint(key_size, sizeof(u64));
+	__uint(value_size, sizeof(char [CW_SYS_HEADER_VAL_LENGTH]));
+	__uint(max_entries, MAX_CONCURRENT);
+} http_server_context_sys_headers SEC(".maps");
+
 // Injected in init
 // volatile const u64 ctx_ptr_pos;
 // volatile const u64 headers_ptr_pos;
@@ -124,196 +131,6 @@ struct {
 //}
 //}
 
-static __always_inline struct span_context *extract_context_from_req_headers_del(void *headers_ptr_ptr) {
-	void *headers_ptr;
-	long res;
-	res = bpf_probe_read(&headers_ptr, sizeof(headers_ptr), headers_ptr_ptr);
-	if (res < 0) {
-		return NULL;
-	}
-	u64 headers_count = 0;
-	res = bpf_probe_read(&headers_count, sizeof(headers_count), headers_ptr);
-	if (res < 0) {
-		return NULL;
-	}
-	if (headers_count == 0) {
-		return NULL;
-	}
-	unsigned char log_2_bucket_count;
-	res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), headers_ptr + 9);
-	if (res < 0) {
-		return NULL;
-	}
-	u64 bucket_count = 1 << log_2_bucket_count;
-	__u64 pid_tgid = bpf_get_current_pid_tgid();
-	__u32 tgid = pid_tgid >> 32;
-	struct ebpf_proc_info *proc_info =
-			bpf_map_lookup_elem(&proc_info_map, &tgid);
-    if(!proc_info)
-    {
-        return 0;
-    }
-	
-	// Check if Go version >= 1.24 (Swiss Tables)
-	if (proc_info->version >= GO_VERSION(1, 24, 0)) {
-		// Swiss Tables uses dirPtr instead of buckets, structure is incompatible
-		// Skip header reading for Go 1.24+
-		return NULL;
-	}
-	
-	void *header_buckets;
-	res = bpf_probe_read(&header_buckets, sizeof(header_buckets), (void *) (headers_ptr + proc_info->buckets_ptr_pos));
-	if (res < 0) {
-		return NULL;
-	}
-	u32 map_id = 0;
-	struct map_bucket *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
-	if (!map_value) {
-		return NULL;
-	}
-	for (u32 j = 0; j < MAX_BUCKETS; j++) {
-		if (j >= bucket_count) {
-			break;
-		}
-		res = bpf_probe_read(map_value, sizeof(struct map_bucket), header_buckets + (j * sizeof(struct map_bucket)));
-		if (res < 0) {
-			continue;
-		}
-
-//		for (u32 i = 0; i < 8; i++) {
-		u32 i = 0;
-			if (map_value->tophash[i] != 0 && map_value->keys[i].len == CW_HEADER_KEY_LENGTH) {
-//				char current_header_key[CW_HEADER_KEY_LENGTH];
-//				bpf_probe_read(current_header_key, sizeof(current_header_key), map_value->keys[i].str);
-			for (int ii = 0; ii < CW_HEADER_KEY_LENGTH; ii++) {
-				if (map_value->keys[i].str[ii] != CW_HEADER_KEY_VAL[i] && map_value->keys[i].str[ii] != CW_HEADER_KEY_UFIRST_VAL[ii]) {
-//					goto outer_loop;
-				}
-			}
-//				continue;
-			}
-//			if (map_value->keys[i].len != CW_HEADER_KEY_LENGTH) {
-//				continue;
-//			}
-
-//			char current_header_key[CW_HEADER_KEY_LENGTH];
-//			bpf_probe_read(current_header_key, sizeof(current_header_key), map_value->keys[i].str);
-
-
-//
-//			struct header_key * current_header_key = bpf_map_lookup_elem(&header_keys_map, &map_id);
-//			if (current_header_key) {
-//				bpf_probe_read(current_header_key->str, sizeof(current_header_key->str),  map_value->keys[i].str);
-//			}
-//
-//			for (int i = 0; i < CW_HEADER_KEY_LENGTH; i++) {
-//				if (current_header_key[i] != CW_HEADER_KEY_VAL[i] && current_header_key[i] != CW_HEADER_KEY_UFIRST_VAL[i]) {
-//					goto outer_loop;
-//				}
-//			}
-//
-//			void *traceparent_header_value_ptr = map_value->values[i].array;
-//			struct go_string_ot traceparent_header_value_go_str;
-//			res = bpf_probe_read(&traceparent_header_value_go_str, sizeof(traceparent_header_value_go_str),
-//			                     traceparent_header_value_ptr);
-//			// 00-95b5ec2b81e2374a4a27ce36ab71d349-18f65a5a3ab22213-02
-//			cw_bpf_debug("traceparent_header_value_go_str.str:%s", traceparent_header_value_go_str.str);
-//
-//			if (res < 0) {
-//				return NULL;
-//			}
-//
-//			// char traceparent_header_value[130];
-//			int key = 0;
-//			char *traceparent_header_value;
-//			traceparent_header_value = bpf_map_lookup_elem(&go_large_array_map, &key);
-//
-//			res = bpf_probe_read(&traceparent_header_value, sizeof(traceparent_header_value),
-//			                     traceparent_header_value_go_str.str);
-//
-//
-//			if (res < 0) {
-//				return NULL;
-//			}
-//			struct span_context *parent_span_context = bpf_map_lookup_elem(&parent_span_context_storage_map, &map_id);
-//			if (!parent_span_context) {
-//				cw_bpf_debug("no parent_span_context");
-//				return NULL;
-//			}
-//			struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&cw_parent_span_context_storage_map, &map_id);
-//			if (!cw_parent_span_context) {
-//				cw_bpf_debug("no cw_parent_span_context");
-//				return NULL;
-//			}
-//
-//			w3c_string_to_span_context(traceparent_header_value, parent_span_context);
-//
-//			cw_string_to_span_context(traceparent_header_value, cw_parent_span_context);
-//
-//			// 保存sc
-//			cw_save_parent_tracking_span(cw_parent_span_context);
-//
-//			return parent_span_context;
-//			outer_loop:
-//			continue;
-//		}
-	}
-	return NULL;
-}
-
-// 获取 get_map_bucket
-static __always_inline struct map_bucket *get_map_bucket(void *headers_ptr_ptr) {
-	void *headers_ptr;
-	long res;
-	res = bpf_probe_read(&headers_ptr, sizeof(headers_ptr), headers_ptr_ptr);
-	if (res < 0) {
-		return NULL;
-	}
-	u64 headers_count = 0;
-	res = bpf_probe_read(&headers_count, sizeof(headers_count), headers_ptr);
-	if (res < 0) {
-		return NULL;
-	}
-	if (headers_count == 0) {
-		return NULL;
-	}
-	unsigned char log_2_bucket_count;
-	res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), headers_ptr + 9);
-	if (res < 0) {
-		return NULL;
-	}
-	u64 bucket_count = 1 << log_2_bucket_count;
-	__u64 pid_tgid = bpf_get_current_pid_tgid();
-	__u32 tgid = pid_tgid >> 32;
-	struct ebpf_proc_info *proc_info =
-			bpf_map_lookup_elem(&proc_info_map, &tgid);
-    if(!proc_info)
-    {
-        return NULL;
-    }
-	void *header_buckets;
-	res = bpf_probe_read(&header_buckets, sizeof(header_buckets), (void *) (headers_ptr + proc_info->buckets_ptr_pos));
-	if (res < 0) {
-		return NULL;
-	}
-	u32 map_id = 0;
-	struct map_bucket *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
-	if (!map_value) {
-		return NULL;
-	}
-	__builtin_memset(map_value, 0, sizeof(struct map_bucket));
-
-	for (u32 j = 0; j < 8; j++) {
-		if (j >= bucket_count) {
-			break;
-		}
-		res = bpf_probe_read(map_value, sizeof(struct map_bucket), header_buckets + (j * sizeof(struct map_bucket)));
-		if (res == 0) {
-			return map_value;
-		}
-	}
-	return NULL;
-}
 
 
 MAP_BUCKET_DEFINITION(go_string_ot,  go_slice_ot)
@@ -329,159 +146,13 @@ extract_context_from_req_headers_pre_parsed(void *key) {
 	return header_val;
 }
 
-static __always_inline char *extract_context_from_req_headers_go_map(void *headers_ptr_ptr)
-{
-	void *headers_ptr;
-	long res;
-	res = bpf_probe_read(&headers_ptr, sizeof(headers_ptr), headers_ptr_ptr);
-	if (res < 0)
-	{
-		return NULL;
-	}
-	u64 headers_count = 0;
-	res = bpf_probe_read(&headers_count, sizeof(headers_count), headers_ptr);
-	if (res < 0)
-	{
-		return NULL;
-	}
-	if (headers_count == 0)
-	{
-		return NULL;
-	}
-	unsigned char log_2_bucket_count;
-	res = bpf_probe_read(&log_2_bucket_count, sizeof(log_2_bucket_count), headers_ptr + 9);
-	if (res < 0)
-	{
-		return NULL;
-	}
-	u64 bucket_count = 1 << log_2_bucket_count;
-	void *header_buckets;
-	/**/
-	__u64 pid_tgid = bpf_get_current_pid_tgid();
-	__u32 tgid = pid_tgid >> 32;
-	struct ebpf_proc_info *proc_info =
-			bpf_map_lookup_elem(&proc_info_map, &tgid);
-	if(!proc_info)
-	{
-		return NULL;
-	}
-	/**/
-
-	res = bpf_probe_read(&header_buckets, sizeof(header_buckets), (void*)(headers_ptr + proc_info->buckets_ptr_pos));
-	if (res < 0)
-	{
-		return NULL;
-	}
-	u32 map_id = 0;
-	MAP_BUCKET_TYPE(go_string_ot, go_slice_ot) *map_value = bpf_map_lookup_elem(&golang_mapbucket_storage_map, &map_id);
-	if (!map_value)
-	{
-		return NULL;
-	}
-
-	for (u64 j = 0; j < MAX_BUCKETS; j++)
-	{
-		if (j >= bucket_count)
-		{
-			break;
-		}
-		res = bpf_probe_read(map_value, sizeof(MAP_BUCKET_TYPE(go_string_ot, go_slice_ot)), header_buckets + (j * sizeof(MAP_BUCKET_TYPE(go_string_ot, go_slice_ot))));
-		if (res < 0)
-		{
-			continue;
-		}
-		for (u64 i = 0; i < 8; i++)
-		{
-			if (map_value->tophash[i] == 0)
-			{
-				continue;
-			}
-			if (map_value->keys[i].len != CW_HEADER_KEY_LENGTH)
-			{
-				continue;
-			}
-			char current_header_key[CW_HEADER_KEY_LENGTH];
-			bpf_probe_read(current_header_key, sizeof(current_header_key), map_value->keys[i].str);
-			if (!bpf_memcmp(current_header_key, CW_HEADER_KEY_VAL, CW_HEADER_KEY_LENGTH) && !bpf_memcmp(current_header_key, CW_HEADER_KEY_UFIRST_VAL, CW_HEADER_KEY_LENGTH))
-			{
-				continue;
-			}
-			void *traceparent_header_value_ptr = map_value->values[i].array;
-			struct go_string_ot traceparent_header_value_go_str;
-			res = bpf_probe_read(&traceparent_header_value_go_str, sizeof(traceparent_header_value_go_str), traceparent_header_value_ptr);
-			if (res < 0)
-			{
-				return NULL;
-			}
-			if (traceparent_header_value_go_str.len != CW_HEADER_VAL_LENGTH)
-			{
-				continue;
-			}
-			char traceparent_header_value2[CW_HEADER_VAL_LENGTH];
-			res = bpf_probe_read(&traceparent_header_value2, sizeof(traceparent_header_value2), traceparent_header_value_go_str.str);
-			if (res < 0)
-			{
-				return NULL;
-			}
-//			bpf_printk("has cw header111 j=%d i=%d %s", j, i,traceparent_header_value_go_str.str);
-
-			return traceparent_header_value_go_str.str;
-//			w3c_string_to_span_context(traceparent_header_value, parent_span_context);
-//			return 0;
-		}
-	}
-	return NULL;
-}
 
 static __always_inline char *
 extract_context_from_req_headers(void *key, void *headers_ptr_ptr, __u64 use_swiss) {
-	if (use_swiss == 1) {
+//	if (use_swiss == 1) {
 		return extract_context_from_req_headers_pre_parsed(key);
-	}
-	return extract_context_from_req_headers_go_map(headers_ptr_ptr);
-}
-
-// 获取 header_val
-static __always_inline char *get_header_val(struct map_bucket *map_value,u32 off,u32 count) {
-	for (u32 i = off; i < count; i++) {
-		if (map_value->tophash[i] != 0 && map_value->keys[i].len == CW_HEADER_KEY_LENGTH) {
-			char current_header_key[CW_HEADER_KEY_LENGTH];
-			bpf_probe_read(current_header_key, sizeof(current_header_key), map_value->keys[i].str);
-			if ((current_header_key[0] == CW_HEADER_KEY_VAL[0]
-			     || current_header_key[0] == CW_HEADER_KEY_UFIRST_VAL[0])
-			    && current_header_key[1] == CW_HEADER_KEY_UFIRST_VAL[1]
-			    && current_header_key[2] == CW_HEADER_KEY_UFIRST_VAL[2]
-			    && current_header_key[3] == CW_HEADER_KEY_UFIRST_VAL[3]
-			    && current_header_key[4] == CW_HEADER_KEY_UFIRST_VAL[4]
-			    && current_header_key[5] == CW_HEADER_KEY_UFIRST_VAL[5]
-			    && current_header_key[6] == CW_HEADER_KEY_UFIRST_VAL[6]) {
-				void *traceparent_header_value_ptr = map_value->values[i].array;
-				struct go_string_ot traceparent_header_value_go_str;
-				long res = bpf_probe_read(&traceparent_header_value_go_str, sizeof(traceparent_header_value_go_str),
-				                          traceparent_header_value_ptr);
-				if (res == 0) {
-					cw_bpf_debug("get_header_val %d-%d %s",off,count,traceparent_header_value_go_str.str);
-					return traceparent_header_value_go_str.str;
-				}
-			}
-		}
-	}
-	return NULL;
-}
-
-// 分段获取 header_val
-static __always_inline char *get_header_val_off(struct map_bucket *map_value) {
-	char *val = get_header_val(map_value, 0, 2);
-	if (val == NULL) {
-		val = get_header_val(map_value, 2, 4);
-	}
-	if (val == NULL) {
-		val = get_header_val(map_value, 4, 6);
-	}
-	if (val == NULL) {
-		val = get_header_val(map_value, 6, 8);
-	}
-	return val;
+//	}
+//	return extract_context_from_req_headers_go_map(headers_ptr_ptr);
 }
 
 
@@ -542,6 +213,14 @@ int uprobe_HandlerFunc_ServeHTTP(struct pt_regs *ctx) {
 	}
 	__builtin_memset(cw_parent_span_context, 0, sizeof(struct apm_span_context));
 
+	// parentSys parentService
+	char *header_sys_val = bpf_map_lookup_elem(&http_server_context_sys_headers, &key);
+	if (header_sys_val) {
+		bpf_printk("has sys");
+		bpf_probe_read(&cw_parent_span_context->sysvs, sizeof(cw_parent_span_context->sysvs), header_sys_val);
+		bpf_printk("has sys %s", cw_parent_span_context->sysvs);
+	}
+
 	if (traceparent_header_value != NULL) {
 		cw_bpf_debug("traceparent_header_value != NULL");
 
@@ -618,10 +297,12 @@ int uprobe_HandlerFunc_ServeHTTP_Returns(struct pt_regs *ctx) {
 	if (uprobe_data == NULL) {
 		cw_bpf_debug("uprobe/HandlerFunc_ServeHTTP_Returns: entry_state is NULL");
 		bpf_map_delete_elem(&http_server_context_headers, &key);
+		bpf_map_delete_elem(&http_server_context_sys_headers, &key);
 		return 0;
 	}
 	bpf_map_delete_elem(&http_server_uprobes, &key);
 	bpf_map_delete_elem(&http_server_context_headers, &key);
+	bpf_map_delete_elem(&http_server_context_sys_headers, &key);
 	struct http_server_span_t *http_server_span = &uprobe_data->span;
 //	void *resp_ptr = (void *) uprobe_data->resp_ptr;
 //	void *req_ptr = NULL;
@@ -673,5 +354,18 @@ int uprobe_textproto_Reader_readContinuedLineSlice_Returns(struct pt_regs *ctx)
 			bpf_map_update_elem(&http_server_context_headers, &key, &header_val, BPF_ANY);
 		}
 	}
+	// cwother: 08:service:03:tag
+	// 解析 cwother header (变长,需要检查是否匹配)
+	if (len >= (CW_SYS_HEADER_KEY_LENGTH + 2 + 8)) {  // 至少 "cwother: NN:name:MM " 的长度
+		long cw_sys_header_native = 0x3A726568746F7763LL; // 小端序下的 "cwother:"
+		__u64 key64 = 0;
+		bpf_probe_read_user(&key64, sizeof(key64), buf);
+		if (key64 == cw_sys_header_native) {
+			char header_val[CW_SYS_HEADER_VAL_LENGTH] = {};
+			bpf_probe_read_user(header_val, sizeof(header_val), buf + CW_SYS_HEADER_KEY_LENGTH + 2);
+			cw_bpf_debug("Swiss Map:%s key %llu", header_val,key);
+			bpf_map_update_elem(&http_server_context_sys_headers, &key, &header_val, BPF_ANY);
+		}
+	}
 	return 0;
 }

+ 5 - 4
ebpftracer/l7/l7.go

@@ -232,8 +232,9 @@ type RequestData struct {
 		SpanIdFrom     string
 		TypeFrom       string
 	}
-	ErrorMsg string
-	IsTls    bool
-	MQTopic  string // MQ topic (e.g., Kafka topic)
-	MQKey    string // MQ key (e.g., Kafka message key)
+	SysvcFrom string // cwother header value: NN:ParentServiceName:MM:ParentServiceSysTag
+	ErrorMsg  string
+	IsTls     bool
+	MQTopic   string // MQ topic (e.g., Kafka topic)
+	MQKey     string // MQ key (e.g., Kafka message key)
 }

+ 43 - 0
ebpftracer/tls.go

@@ -512,6 +512,49 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32, appInfo *AppInfo, codeType uint1
 			klog.WithField("pid", pid).Debugln("info.StartAddr", info.StartAddr)
 			klog.WithField("pid", pid).Debugln("info.EndAddr", info.EndAddr)
 
+			// 构建 sysvc 值:{app_name_len}:app_name:{appServiceType_len}:appServiceType:{SysTagLen}[:SysTag]
+			// appServiceType 固定为 "APPLICATION"
+			appName := appInfo.AppName
+			nodeInfo := NODE_INFO.GetNodeInfo()
+			sysTag := ""
+			if nodeInfo != nil {
+				sysTag = nodeInfo.SysTag
+			}
+			appServiceType := "APPLICATION"
+
+			appNameLen := len(appName)
+			appServiceTypeLen := len(appServiceType)
+			sysTagLen := len(sysTag)
+
+			// 限制长度,避免超出数组大小
+			if appNameLen > 32 {
+				appNameLen = 32
+				appName = appName[:32]
+			}
+			if sysTagLen > 32 {
+				sysTagLen = 32
+				sysTag = sysTag[:32]
+			}
+
+			// 格式:{app_name_len}:app_name:{appServiceType_len}:appServiceType[:{SysTagLen}:SysTag]
+			// 如果 sysTag 为空,则为 {app_name_len}:app_name:{appServiceType_len}:appServiceType
+			// 如果 sysTag 不为空,则为 {app_name_len}:app_name:{appServiceType_len}:appServiceType:{SysTagLen}:SysTag
+			// 长度不足2位时前面补0,例如:08:service:12:APPLICATION 或 08:service:12:APPLICATION:03:tag
+			var sysvcStr string
+			if sysTagLen == 0 {
+				sysvcStr = fmt.Sprintf("%02d:%s:%02d:%s", appNameLen, appName, appServiceTypeLen, appServiceType)
+			} else {
+				sysvcStr = fmt.Sprintf("%02d:%s:%02d:%s:%02d:%s", appNameLen, appName, appServiceTypeLen, appServiceType, sysTagLen, sysTag)
+			}
+
+			// 复制到字节数组,确保不超过 76 字节
+			sysvcBytes := []byte(sysvcStr)
+			if len(sysvcBytes) > 76 {
+				sysvcBytes = sysvcBytes[:76]
+			}
+			copy(info.Sysvc[:], sysvcBytes)
+			klog.Debugf("[AttachGoTlsUprobes] Sysvc constructed: %s", sysvcStr)
+
 			klog.Infof("[AttachGoTlsUprobes] Updating proc_info map")
 			_, err = tracer.UpdateProcInfoToMap(t.collection, pid, info)
 			if err != nil {

+ 46 - 0
ebpftracer/tracer.go

@@ -554,6 +554,7 @@ type l7Event struct {
 	AppIdFrom           HashByte
 	SpanIdFrom          HashByte
 	TypeFrom            [1]byte
+	SysvcFrom           [76]byte // cwother header value: NN:ParentServiceName:MM:ParentServiceSysTag
 	RPCTarget           [64]byte
 	ErrorMsg            HashByte128
 	MQ                  struct {
@@ -807,6 +808,9 @@ func runEventsReader(name string, r *perf.Reader, ch chan<- Event, typ perfMapTy
 				req.ParentSpanContext.AppIdFrom = hex.EncodeToString(v.AppIdFrom[:])
 				req.ParentSpanContext.SpanIdFrom = hex.EncodeToString(v.SpanIdFrom[:])
 				req.ParentSpanContext.TypeFrom = hex.EncodeToString(v.TypeFrom[:])
+				req.SysvcFrom = utils.BytesToString(v.SysvcFrom[:])
+				fmt.Println("req.SysvcFrom")
+				fmt.Println(req.SysvcFrom)
 				// klog.Debugf("req.ParentSpanContext.TraceIdFrom %s", req.ParentSpanContext.TraceIdFrom)
 				// klog.Debugf("req.ParentSpanContext.TypeFrom %s", req.ParentSpanContext.TypeFrom)
 				req.SAddr = ipPort(v.SAddr, v.Sport)
@@ -905,6 +909,7 @@ func ipPort(ip [16]byte, port uint16) netaddr.IPPort {
 }
 
 func (t *Tracer) InitKProcInfo(pid uint32, appInfo *AppInfo) error {
+	fmt.Println("InitKProcInfo111111111111111111111111111111111")
 	var err error
 	var info EbpfProcInfo
 	if appInfo.EBPFProcInfo == nil {
@@ -918,6 +923,47 @@ func (t *Tracer) InitKProcInfo(pid uint32, appInfo *AppInfo) error {
 		info.AppId = appInfo.AppIdHash.HashtVal
 	}
 
+	// 构建 sysvc 值:{app_name_len}:app_name:{appServiceType_len}:appServiceType:{SysTagLen}[:SysTag]
+	// appServiceType 固定为 "APPLICATION"
+	appName := appInfo.AppName
+	nodeInfo := NODE_INFO.GetNodeInfo()
+	sysTag := ""
+	if nodeInfo != nil {
+		sysTag = nodeInfo.SysTag
+	}
+	appServiceType := "APPLICATION"
+
+	appNameLen := len(appName)
+	appServiceTypeLen := len(appServiceType)
+	sysTagLen := len(sysTag)
+
+	// 限制长度,避免超出数组大小
+	if appNameLen > 32 {
+		appNameLen = 32
+		appName = appName[:32]
+	}
+	if sysTagLen > 32 {
+		sysTagLen = 32
+		sysTag = sysTag[:32]
+	}
+
+	// 格式:{app_name_len}:app_name:{appServiceType_len}:appServiceType[:{SysTagLen}:SysTag]
+	// 如果 sysTag 为空,则为 {app_name_len}:app_name:{appServiceType_len}:appServiceType
+	// 如果 sysTag 不为空,则为 {app_name_len}:app_name:{appServiceType_len}:appServiceType:{SysTagLen}:SysTag
+	// 长度不足2位时前面补0,例如:08:service:12:APPLICATION 或 08:service:12:APPLICATION:03:tag
+	var sysvcStr string
+	if sysTagLen == 0 {
+		sysvcStr = fmt.Sprintf("%02d:%s:%02d:%s", appNameLen, appName, appServiceTypeLen, appServiceType)
+	} else {
+		sysvcStr = fmt.Sprintf("%02d:%s:%02d:%s:%02d:%s", appNameLen, appName, appServiceTypeLen, appServiceType, sysTagLen, sysTag)
+	}
+
+	// 复制到字节数组,确保不超过 76 字节
+	sysvcBytes := []byte(sysvcStr)
+	if len(sysvcBytes) > 76 {
+		sysvcBytes = sysvcBytes[:76]
+	}
+	copy(info.Sysvc[:], sysvcBytes)
 	_, err = tracer.UpdateProcInfoToMap(t.collection, pid, info)
 	if err != nil {
 		klog.Error("failed to update program info", err)

+ 119 - 4
pkg/go.opentelemetry.io/otel/exporters/otlp/otlptrace/apm_exporter.go

@@ -90,10 +90,13 @@ type RootDataT struct {
 	DestinationAddr string        `json:"destination_addr"`
 	UserAgent       string        `json:"user_agent"`
 	// op 新增字段
-	Pid         uint32 `json:"pid"`
-	ContainerID string `json:"container_id"`
-	Sys         string `json:"sys"`
-	SystemUUID  string `json:"system_uuid"`
+	Pid             uint32 `json:"pid"`
+	ContainerID     string `json:"container_id"`
+	Sys             string `json:"sys"`
+	SystemUUID      string `json:"system_uuid"`
+	ParentSys       string `json:"parent_sys"`        // from cwother header: SysTag
+	AppNameFrom     string `json:"app_name_from"`     // from cwother header: app_name
+	ServiceTypeFrom string `json:"service_type_from"` // from cwother header: appServiceType
 }
 
 // ParamStruct 定义目标结构
@@ -817,6 +820,20 @@ func buildAppMapFromEvent(traceRoot *RootDataT, sd apmTraceSpan) int {
 		// root tag
 		case "server.oper_type":
 			traceRoot.OperType = attr.Value.AsString()
+		case "server.sysvc_from":
+			// 解析 SysvcFrom 格式:{app_name_len}:app_name:{appServiceType_len}:appServiceType:{SysTagLen}[:SysTag]
+			// 例如:08:eBPF-APP:12:APPLICATION:00 或 08:eBPF-APP:12:APPLICATION:03:tag
+			sysvcFrom := attr.Value.AsString()
+			appNameFrom, serviceTypeFrom, parentSys := parseSysvcFrom(sysvcFrom)
+			traceRoot.AppNameFrom = appNameFrom
+			traceRoot.ServiceTypeFrom = serviceTypeFrom
+			traceRoot.ParentSys = parentSys
+		case "service.parent_sys":
+			// 支持直接从 attribute 传递
+			traceRoot.ParentSys = attr.Value.AsString()
+		case "app_name_from":
+			// 支持直接从 attribute 传递
+			traceRoot.AppNameFrom = attr.Value.AsString()
 		}
 	}
 	traceRoot.Maps = append(traceRoot.Maps, mNode)
@@ -1261,3 +1278,101 @@ func Md5ToInt64(strParam string, Len int) int64 {
 func cleanNsTime(time int64) (uint64, uint64) {
 	return uint64(time), uint64(math.Round(float64(time) / 1e6))
 }
+
+func parseLen2(s string, i int) (int, bool) {
+	if len(s) < i+2 {
+		return 0, false
+	}
+	c1, c2 := s[i], s[i+1]
+	if c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' {
+		return 0, false
+	}
+	return int(c1-'0')*10 + int(c2-'0'), true
+}
+
+func parseSysvcFrom(sysvcFrom string) (string, string, string) {
+	// 新格式:{app_name_len}:app_name:{appServiceType_len}:appServiceType[:{SysTagLen}:SysTag]
+	// 例如:08:eBPF-APP:12:APPLICATION 或 08:eBPF-APP:12:APPLICATION:03:tag
+	// 最小长度:12 (如 "08:x:12:APPLICATION")
+	if len(sysvcFrom) < 12 {
+		return "", "", ""
+	}
+
+	// 解析 app_name_len(前2位)
+	appNameLen, ok := parseLen2(sysvcFrom, 0)
+	if !ok || appNameLen < 0 || appNameLen > 32 {
+		return "", "", ""
+	}
+
+	// 检查第一个冒号
+	if len(sysvcFrom) < 3 || sysvcFrom[2] != ':' {
+		return "", "", ""
+	}
+
+	// 提取 app_name(从位置 3 开始,长度为 appNameLen)
+	appNameStart := 3
+	appNameEnd := appNameStart + appNameLen
+	if len(sysvcFrom) < appNameEnd {
+		return "", "", ""
+	}
+	appNameFrom := sysvcFrom[appNameStart:appNameEnd]
+
+	// 检查 app_name 后的冒号
+	if len(sysvcFrom) < appNameEnd+1 || sysvcFrom[appNameEnd] != ':' {
+		return appNameFrom, "", ""
+	}
+
+	// 解析 appServiceType_len(app_name 后的2位)
+	appServiceTypeLenStart := appNameEnd + 1
+	appServiceTypeLen, ok := parseLen2(sysvcFrom, appServiceTypeLenStart)
+	if !ok || appServiceTypeLen < 0 || appServiceTypeLen > 32 {
+		return appNameFrom, "", ""
+	}
+
+	// 检查 appServiceType_len 后的冒号
+	appServiceTypeStart := appServiceTypeLenStart + 2
+	if len(sysvcFrom) < appServiceTypeStart+1 || sysvcFrom[appServiceTypeStart] != ':' {
+		return appNameFrom, "", ""
+	}
+
+	// 提取 appServiceType
+	appServiceTypeStart++
+	appServiceTypeEnd := appServiceTypeStart + appServiceTypeLen
+	if len(sysvcFrom) < appServiceTypeEnd {
+		return appNameFrom, "", ""
+	}
+	serviceTypeFrom := sysvcFrom[appServiceTypeStart:appServiceTypeEnd]
+
+	// 检查 appServiceType 后的冒号
+	if len(sysvcFrom) < appServiceTypeEnd+1 || sysvcFrom[appServiceTypeEnd] != ':' {
+		return appNameFrom, serviceTypeFrom, ""
+	}
+
+	// 解析 sysTagLen(appServiceType 后的2位)
+	sysTagLenStart := appServiceTypeEnd + 1
+	sysTagLen, ok := parseLen2(sysvcFrom, sysTagLenStart)
+	if !ok || sysTagLen < 0 || sysTagLen > 32 {
+		return appNameFrom, serviceTypeFrom, ""
+	}
+
+	// 如果 sysTagLen == 0,则没有 sysTag
+	if sysTagLen == 0 {
+		return appNameFrom, serviceTypeFrom, ""
+	}
+
+	// 检查 sysTagLen 后的冒号
+	sysTagStart := sysTagLenStart + 2
+	if len(sysvcFrom) < sysTagStart+1 || sysvcFrom[sysTagStart] != ':' {
+		return appNameFrom, serviceTypeFrom, ""
+	}
+
+	// 提取 sysTag
+	sysTagStart++
+	sysTagEnd := sysTagStart + sysTagLen
+	if len(sysvcFrom) < sysTagEnd {
+		return appNameFrom, serviceTypeFrom, ""
+	}
+	parentSys := sysvcFrom[sysTagStart:sysTagEnd]
+
+	return appNameFrom, serviceTypeFrom, parentSys
+}

+ 5 - 0
tracing/apm_tracing.go

@@ -321,6 +321,11 @@ func (t *Trace) TraceEndEvent(r *l7.RequestData) {
 	klog.Debugf("TraceEndEvent SAddr.String %s", r.SAddr.String())
 	klog.Debugf("TraceEndEvent DAddr.String %s", r.DAddr.String())
 
+	// 添加 SysvcFrom 到 attributes
+	if r.SysvcFrom != "" {
+		attr = append(attr, attribute.String("server.sysvc_from", r.SysvcFrom))
+	}
+
 	t.appendTimestamp(&attr, r.StartAt, r.EndAt, r.Duration.Nanoseconds())
 	t.span.SetAttributes(attr...)
 	t.endReadyEvent(r.EventCount)

+ 2 - 0
utils/modelse/bpf_struct.go

@@ -234,6 +234,8 @@ type EbpfProcInfo struct {
 	// net.TCPAddr offsets
 	TcpAddrIPOffset   uint64 // net.TCPAddr.IP field offset
 	TcpAddrPortOffset uint64 // net.TCPAddr.Port field offset
+	// cwother header value: {app_name_len}:app_name:{SysTagLen}[:SysTag]
+	Sysvc [76]byte // CW_SYS_HEADER_VAL_LENGTH
 }
 
 type allowPortBitmap struct {