Repository: alibaba/opentelemetry-go-auto-instrumentation
Pull request #413: feat: support kafka-go
Author: login: DeepSeaCat
Created: 2025-04-25T10:23:56Z | Merged: 2025-05-21T06:25:22Z

support segmentio/kafka-go

https://github.com/segmentio/kafka-go


Diff:
diff --git a/Makefile b/Makefile
index 079a50ea8..076cb5083 100644
--- a/Makefile
+++ b/Makefile
@@ -42,8 +42,8 @@ else
 endif
 
 VERSION := $(MAIN_VERSION)_$(COMMIT_ID)
-XVERSION := -X=$(MOD_NAME)/tool/config.ToolVersion=$(VERSION) -X=$(MOD_NAME)/pkg/inst-api/version.Tag=v$(VERSION)
-LDFLAGS := -ldflags="$(XVERSION) $(STRIP_DEBUG)"
+XVALUES := -X=$(MOD_NAME)/tool/config.ToolVersion=$(VERSION) -X=$(MOD_NAME)/tool/config.BuildPath=$(PWD)/pkg -X=$(MOD_NAME)/pkg/inst-api/version.Tag=v$(VERSION)
+LDFLAGS := -ldflags="$(XVALUES) $(STRIP_DEBUG)"
 GCFLAGS := -gcflags="all=-trimpath=$(PWD)" -asmflags="all=-trimpath=$(PWD)" 
 BUILD_CMD = CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build -a $(LDFLAGS) $(GCFLAGS) -o $(3) ./tool/otel
 
diff --git a/go.mod b/go.mod
index 5c567e085..b1a18f7d0 100755
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.23.0
 
 require (
 	github.com/dave/dst v0.27.3
+	github.com/docker/docker v28.0.1+incompatible
 	github.com/docker/go-connections v0.5.0
 	github.com/testcontainers/testcontainers-go v0.37.0
 	github.com/testcontainers/testcontainers-go/modules/mysql v0.37.0
@@ -21,7 +22,6 @@ require (
 	github.com/cpuguy83/dockercfg v0.3.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/distribution/reference v0.6.0 // indirect
-	github.com/docker/docker v28.1.1+incompatible // indirect
 	github.com/docker/go-units v0.5.0 // indirect
 	github.com/ebitengine/purego v0.8.3 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
diff --git a/pkg/go.mod b/pkg/go.mod
index e24f78376..c1373da69 100644
--- a/pkg/go.mod
+++ b/pkg/go.mod
@@ -31,6 +31,7 @@ require (
 	github.com/rabbitmq/amqp091-go v1.10.0
 	github.com/redis/go-redis/v9 v9.0.5
 	github.com/rs/zerolog v1.31.0
+	github.com/segmentio/kafka-go v0.4.48
 	github.com/sirupsen/logrus v1.9.3 // not minimal, but consistent with older alibaba-otel
 	github.com/stretchr/testify v1.10.0
 	github.com/tmc/langchaingo v0.1.13
@@ -182,6 +183,7 @@ require (
 	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/philhofer/fwd v1.1.2 // indirect
+	github.com/pierrec/lz4/v4 v4.1.21 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pkoukk/tiktoken-go v0.1.6 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -239,6 +241,7 @@ require (
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	stathat.com/c/consistent v1.0.0 // indirect
 	trpc.group/trpc-go/tnet v1.0.1 // indirect
 	trpc.group/trpc/trpc-protocol/pb/go/trpc v1.0.0 // indirect
 )
diff --git a/pkg/go.sum b/pkg/go.sum
index f6a78f0e0..f7964994d 100644
--- a/pkg/go.sum
+++ b/pkg/go.sum
@@ -28,6 +28,7 @@ git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3p
 github.com/AssemblyAI/assemblyai-go-sdk v1.3.0 h1:AtOVgGxUycvK4P4ypP+1ZupecvFgnfH+Jsum0o5ILoU=
 github.com/AssemblyAI/assemblyai-go-sdk v1.3.0/go.mod h1:H0naZbvpIW49cDA5ZZ/gggeXqi7ojSGB1mqshRk6kNE=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
@@ -129,6 +130,8 @@ github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsVi
 github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/apache/rocketmq-client-go/v2 v2.1.2 h1:yt73olKe5N6894Dbm+ojRf/JPiP0cxfDNNffKwhpJVg=
+github.com/apache/rocketmq-client-go/v2 v2.1.2/go.mod h1:6I6vgxHR3hzrvn+6n/4mrhS+UTulzK/X9LB2Vk1U5gE=
 github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI=
 github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -172,6 +175,7 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chenzhuoyu/iasm v0.0.0-20230222070914-0b1b64b0e762/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
@@ -322,6 +326,7 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI=
 github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -335,6 +340,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
 github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -372,6 +378,7 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20220608213341-c488b8fa1db3/go.mod h1:gSuNB+gJaOiQKLEZ+q+PK9Mq3SOzhRcw2GsGS/FhYDk=
 github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
 github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
@@ -411,6 +418,7 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
 github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
@@ -461,6 +469,7 @@ github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgy
 github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
 github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
 github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@@ -545,6 +554,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
 github.com/nikolalohinski/gonja v1.5.3 h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c=
 github.com/nikolalohinski/gonja v1.5.3/go.mod h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
 github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg=
@@ -552,9 +562,16 @@ github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJr
 github.com/oleiade/lane v1.0.1/go.mod h1:IyTkraa4maLfjq/GmHR+Dxb4kCMtEGeb+qmhlrQ5Mk4=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
 github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
 github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
 github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
@@ -575,6 +592,9 @@ github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2
 github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
 github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
+github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -620,11 +640,14 @@ github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1Avp
 github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
 github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
 github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
+github.com/segmentio/kafka-go v0.4.48 h1:9jyu9CWK4W5W+SroCe8EffbrRZVqAOkuaLd/ApID4Vs=
+github.com/segmentio/kafka-go v0.4.48/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
@@ -663,6 +686,7 @@ github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZli
 github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
 github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
 github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
 github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -795,6 +819,7 @@ go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU
 go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
+go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0=
@@ -855,6 +880,7 @@ golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeap
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -878,6 +904,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -885,6 +912,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
@@ -924,13 +952,17 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -943,6 +975,7 @@ golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -986,6 +1019,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
@@ -1005,8 +1039,10 @@ golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1015,6 +1051,7 @@ golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roY
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@@ -1124,6 +1161,8 @@ nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYm
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
 sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
+stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
 trpc.group/trpc-go/tnet v1.0.1 h1:Yzqyrgyfm+W742FzGr39c4+OeQmLi7PWotJxrOBtV9o=
 trpc.group/trpc-go/tnet v1.0.1/go.mod h1:s/webUFYWEFBHErKyFmj7LYC7XfC2LTLCcwfSnJ04M0=
 trpc.group/trpc-go/trpc-go v1.0.0 h1:bSbcNpRFEXJONkwMVs8Xd+Mw/mFPUeE9Lcxk7KAaSoU=
diff --git a/pkg/inst-api/utils/scope.go b/pkg/inst-api/utils/scope.go
index 363e75ca8..d13dc6e47 100644
--- a/pkg/inst-api/utils/scope.go
+++ b/pkg/inst-api/utils/scope.go
@@ -41,3 +41,5 @@ const TRPCGO_SERVER_SCOPE_NAME = "pkg/rules/trpc/trpc_server_setup.go"
 const LANGCHAIN_SCOPE_NAME = "pkg/rules/langchain/setup.go"
 const AMQP091_SCOPE_NAME = "pkg/rules/amqp091/setup.go"
 const MCP_SCOPE_NAME = "pkg/rules/mcp/setup.go"
+const KAFKAGO_PRODUCER_SCOPE_NAME = "pkg/rules/segmentio-kafka-go/kafka_producer_setup.go"
+const KAFKAGO_CONSUMER_SCOPE_NAME = "pkg/rules/segmentio-kafka-go/kafka_consumer_setup.go"
diff --git a/pkg/rules/segmentio-kafka-go/kafka_consumer_setup.go b/pkg/rules/segmentio-kafka-go/kafka_consumer_setup.go
new file mode 100644
index 000000000..8f06172be
--- /dev/null
+++ b/pkg/rules/segmentio-kafka-go/kafka_consumer_setup.go
@@ -0,0 +1,62 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
+	"github.com/segmentio/kafka-go"
+	"time"
+	_ "unsafe"
+)
+
+//go:linkname consumerReadMessageOnEnter github.com/segmentio/kafka-go.consumerReadMessageOnEnter
+func consumerReadMessageOnEnter(call api.CallContext, _ interface{}, ctx context.Context) {
+	if !kafkaEnabler.Enable() {
+		return
+	}
+
+	instrumentationData := map[string]interface{}{
+		"parentContext":  ctx,
+		"startTimestamp": time.Now(),
+	}
+	call.SetData(instrumentationData)
+}
+
+//go:linkname consumerReadMessageOnExit github.com/segmentio/kafka-go.consumerReadMessageOnExit
+func consumerReadMessageOnExit(call api.CallContext, message kafka.Message, err error) {
+	if !kafkaEnabler.Enable() {
+		return
+	}
+
+	instrumentationData, ok := call.GetData().(map[string]interface{})
+	if !ok {
+		return
+	}
+
+	parentContext := instrumentationData["parentContext"].(context.Context)
+	startTimestamp := instrumentationData["startTimestamp"].(time.Time)
+	endTimestamp := time.Now()
+
+	consumerRequest := kafkaConsumerReq{msg: message}
+	consumerInstrumenter.StartAndEnd(
+		parentContext,
+		consumerRequest,
+		nil,
+		err,
+		startTimestamp,
+		endTimestamp,
+	)
+}
diff --git a/pkg/rules/segmentio-kafka-go/kafka_data_type.go b/pkg/rules/segmentio-kafka-go/kafka_data_type.go
new file mode 100644
index 000000000..6d850aa7c
--- /dev/null
+++ b/pkg/rules/segmentio-kafka-go/kafka_data_type.go
@@ -0,0 +1,31 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"github.com/segmentio/kafka-go"
+	"net"
+)
+
+type kafkaProducerReq struct {
+	msgs  []*kafka.Message
+	topic string
+	addr  net.Addr
+	async bool
+}
+
+type kafkaConsumerReq struct {
+	msg kafka.Message
+}
diff --git a/pkg/rules/segmentio-kafka-go/kafka_otel_instrumenter.go b/pkg/rules/segmentio-kafka-go/kafka_otel_instrumenter.go
new file mode 100644
index 000000000..7041ae60a
--- /dev/null
+++ b/pkg/rules/segmentio-kafka-go/kafka_otel_instrumenter.go
@@ -0,0 +1,323 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+	"os"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = kafkaInnerEnabler{os.Getenv("OTEL_SEGMENTIO_KAFKA_ENABLED") != "false"}
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+type kafkaInnerEnabler struct {
+	enabled bool
+}
+
+func (k kafkaInnerEnabler) Enable() bool {
+	return k.enabled
+}
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
+	return int64(4 + 1 + 1 + 4 + len(request.msg.Key) + 4 + len(request.msg.Value) + 8)
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageEnvelopSize(request kafkaConsumerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageId(request kafkaConsumerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetClientId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetBatchMessageCount(request kafkaConsumerReq, response any) int64 {
+	return 1
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageHeader(request kafkaConsumerReq, name string) []string {
+	if request.msg.Headers == nil {
+		return nil
+	}
+	var headerValues []string
+	for _, header := range request.msg.Headers {
+		if header.Key == name {
+			headerValues = append(headerValues, string(header.Value))
+		}
+	}
+	return headerValues
+}
+
+// KafkaProducerAttributesExtractor extracts producer attributes
+type kafkaProducerAttributesExtractor struct {
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnStart(attributes []attribute.KeyValue, parentContext context.Context, request kafkaProducerReq) ([]attribute.KeyValue, context.Context) {
+	kafkaAttributes := []attribute.KeyValue{
+		semconv.MessagingSystemKafka,
+		semconv.MessagingDestinationNameKey.String(request.topic),
+		semconv.MessagingOperationName("publish"),
+	}
+	return append(attributes, kafkaAttributes...), parentContext
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnEnd(attributes []attribute.KeyValue, ctx context.Context, request kafkaProducerReq, response any, err error) ([]attribute.KeyValue, context.Context) {
+	return attributes, ctx
+}
+
+// KafkaConsumerAttributesExtractor extracts consumer attributes
+type kafkaConsumerAttributesExtractor struct {
+}
+
+func (extractor *kafkaConsumerAttributesExtractor) OnStart(attributes []attribute.KeyValue, parentContext context.Context, request kafkaConsumerReq) ([]attribute.KeyValue, context.Context) {
+	return attributes, parentContext
+}
+
+func (extractor *kafkaConsumerAttributesExtractor) OnEnd(attributes []attribute.KeyValue, ctx context.Context, request kafkaConsumerReq, response any, err error) ([]attribute.KeyValue, context.Context) {
+	return attributes, ctx
+}
+
+// Build Kafka producer instrumenter
+func buildKafkaProducerInstrumenter() instrumenter.Instrumenter[kafkaProducerReq, any] {
+	builder := instrumenter.Builder[kafkaProducerReq, any]{}
+	return builder.Init().
+		SetInstrumentationScope(instrumentation.Scope{
+			Name:    utils.KAFKAGO_PRODUCER_SCOPE_NAME,
+			Version: version.Tag,
+		}).
+		SetSpanNameExtractor(&message.MessageSpanNameExtractor[kafkaProducerReq, any]{
+			Getter:        kafkaMessageProducerAttrsGetter{},
+			OperationName: message.PUBLISH,
+		}).
+		SetSpanKindExtractor(&instrumenter.AlwaysProducerExtractor[kafkaProducerReq]{}).
+		SetSpanStatusExtractor(&kafkaProducerStatusExtractor{}).
+		AddAttributesExtractor(&kafkaProducerAttributesExtractor{}).
+		BuildPropagatingToDownstreamInstrumenter(
+			func(request kafkaProducerReq) propagation.TextMapCarrier {
+				return kafkaProducerCarrier{messages: request.msgs}
+			},
+			otel.GetTextMapPropagator(),
+		)
+}
+
+// Build Kafka consumer instrumenter
+func buildKafkaConsumerInstrumenter() instrumenter.Instrumenter[kafkaConsumerReq, any] {
+	builder := instrumenter.Builder[kafkaConsumerReq, any]{}
+	return builder.Init().
+		SetInstrumentationScope(instrumentation.Scope{
+			Name:    utils.KAFKAGO_CONSUMER_SCOPE_NAME,
+			Version: version.Tag,
+		}).
+		SetSpanNameExtractor(&message.MessageSpanNameExtractor[kafkaConsumerReq, any]{
+			Getter:        kafkaMessageConsumerAttrsGetter{},
+			OperationName: message.PROCESS,
+		}).
+		SetSpanKindExtractor(&instrumenter.AlwaysConsumerExtractor[kafkaConsumerReq]{}).
+		AddAttributesExtractor(&message.MessageAttrsExtractor[kafkaConsumerReq, any, kafkaMessageConsumerAttrsGetter]{
+			Operation: message.PROCESS,
+		}).
+		AddAttributesExtractor(&kafkaConsumerAttributesExtractor{}).
+		BuildPropagatingFromUpstreamInstrumenter(
+			func(request kafkaConsumerReq) propagation.TextMapCarrier {
+				return kafkaConsumerCarrier{message: request.msg}
+			},
+			otel.GetTextMapPropagator(),
+		)
+}
diff --git a/pkg/rules/segmentio-kafka-go/kafka_producer_setup.go b/pkg/rules/segmentio-kafka-go/kafka_producer_setup.go
new file mode 100644
index 000000000..be7feea07
--- /dev/null
+++ b/pkg/rules/segmentio-kafka-go/kafka_producer_setup.go
@@ -0,0 +1,79 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
+	"github.com/segmentio/kafka-go"
+	_ "unsafe"
+)
+
+//go:linkname producerWriteMessagesOnEnter github.com/segmentio/kafka-go.producerWriteMessagesOnEnter
+func producerWriteMessagesOnEnter(call api.CallContext, writer *kafka.Writer, ctx context.Context, messages ...kafka.Message) {
+	if !kafkaEnabler.Enable() {
+		return
+	}
+
+	// Create pointers to messages for instrumentation
+	messagePointers := make([]*kafka.Message, len(messages))
+	for i := range messages {
+		// Create a copy to avoid issues with loop variable
+		messageCopy := messages[i]
+		messagePointers[i] = &messageCopy
+	}
+
+	// Prepare request data for instrumentation
+	producerRequest := kafkaProducerReq{
+		topic: writer.Topic,
+		addr:  writer.Addr,
+		async: writer.Async,
+		msgs:  messagePointers,
+	}
+
+	// Start instrumentation and get instrumented context
+	instrumentedContext := producerInstrumenter.Start(ctx, producerRequest)
+
+	// Store data for later use in exit hook
+	instrumentationData := map[string]interface{}{
+		"instrumentedContext": instrumentedContext,
+		"producerRequest":     producerRequest,
+	}
+	call.SetData(instrumentationData)
+
+	// Prepare message copies to maintain idempotency
+	messageCopies := make([]kafka.Message, len(messagePointers))
+	for i, msg := range messagePointers {
+		messageCopies[i] = *msg
+	}
+
+	// Update the call parameters with copied messages
+	call.SetParam(2, messageCopies)
+}
+
+//go:linkname producerWriteMessagesOnExit github.com/segmentio/kafka-go.producerWriteMessagesOnExit
+func producerWriteMessagesOnExit(call api.CallContext, err error) {
+	if !kafkaEnabler.Enable() {
+		return
+	}
+
+	// Retrieve stored instrumentation data
+	instrumentationData := call.GetData().(map[string]interface{})
+	instrumentedContext := instrumentationData["instrumentedContext"].(context.Context)
+	producerRequest := instrumentationData["producerRequest"].(kafkaProducerReq)
+
+	// End instrumentation with results
+	producerInstrumenter.End(instrumentedContext, producerRequest, nil, err)
+}
diff --git a/test/segmentio-kafka-go/v0.4.48/base.go b/test/segmentio-kafka-go/v0.4.48/base.go
new file mode 100644
index 000000000..028d3a97a
--- /dev/null
+++ b/test/segmentio-kafka-go/v0.4.48/base.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+	"github.com/segmentio/kafka-go"
+	"os"
+)
+
+const (
+	topicName = "test-topic"
+	groupName = "test-group"
+)
+
+// getKafkaAddress returns Kafka broker address from environment or default
+func getKafkaAddress() string {
+	if addr := os.Getenv("KAFKA_ADDR"); addr != "" {
+		return addr
+	}
+	return "127.0.0.1:9092" // Default Kafka address
+}
+
+// initProducer creates a new Kafka producer configured for our test topic
+func initProducer() *kafka.Writer {
+	return &kafka.Writer{
+		Addr:     kafka.TCP(getKafkaAddress()),
+		Topic:    topicName,
+		Balancer: &kafka.LeastBytes{},
+		Async:    false, // Synchronous writes for testing
+	}
+}
+
+// initConsumer creates a new Kafka consumer configured for our test topic
+func initConsumer() *kafka.Reader {
+	return kafka.NewReader(kafka.ReaderConfig{
+		Brokers:  []string{getKafkaAddress()},
+		Topic:    topicName,
+		GroupID:  groupName,
+		MinBytes: 10e3, // 10KB
+		MaxBytes: 10e6, // 10MB
+	})
+}
diff --git a/test/segmentio-kafka-go/v0.4.48/go.mod b/test/segmentio-kafka-go/v0.4.48/go.mod
new file mode 100644
index 000000000..009163898
--- /dev/null
+++ b/test/segmentio-kafka-go/v0.4.48/go.mod
@@ -0,0 +1,33 @@
+module segmentio-kafka-go
+
+go 1.23.0
+
+replace github.com/alibaba/opentelemetry-go-auto-instrumentation => ../../../../opentelemetry-go-auto-instrumentation
+
+replace github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier => ../../../../opentelemetry-go-auto-instrumentation/test/verifier
+
+require (
+	github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier v0.0.0-20250423111209-a5689b116b5b
+	github.com/segmentio/kafka-go v0.4.48
+	go.opentelemetry.io/otel/sdk v1.35.0
+)
+
+require (
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/klauspost/compress v1.18.0 // indirect
+	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
+	github.com/pierrec/lz4/v4 v4.1.22 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/stretchr/testify v1.10.0 // indirect
+	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+	go.opentelemetry.io/otel v1.35.0 // indirect
+	go.opentelemetry.io/otel/metric v1.35.0 // indirect
+	go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
+	go.opentelemetry.io/otel/trace v1.35.0 // indirect
+	golang.org/x/net v0.38.0 // indirect
+	golang.org/x/sys v0.32.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/test/segmentio-kafka-go/v0.4.48/test_kafka_basic.go b/test/segmentio-kafka-go/v0.4.48/test_kafka_basic.go
new file mode 100644
index 000000000..9b00c6be1
--- /dev/null
+++ b/test/segmentio-kafka-go/v0.4.48/test_kafka_basic.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel/sdk/trace/tracetest"
+)
+
+func main() {
+	ctx := context.Background()
+
+	// Initialize producer with cleanup
+	producer := initProducer()
+	defer producer.Close()
+
+	// Initialize consumer with cleanup
+	consumer := initConsumer()
+	defer consumer.Close()
+
+	// Send message
+	messages := []kafka.Message{kafka.Message{
+		Value: []byte("hello world1"),
+	}, kafka.Message{
+		Value: []byte("hello world2"),
+	}}
+	if err := producer.WriteMessages(ctx, messages...); err != nil {
+		panic(err)
+	}
+
+	// Read message
+	_, err := consumer.ReadMessage(context.Background())
+	if err != nil {
+		panic(err)
+	}
+	_, err = consumer.ReadMessage(context.Background())
+	if err != nil {
+		panic(err)
+	}
+
+	// Verify OpenTelemetry traces
+	verifier.WaitAndAssertTraces(func(stubs []tracetest.SpanStubs) {
+		verifier.VerifyMQPublishAttributes(stubs[0][0], "", "", "", "publish", topicName, "kafka")
+		verifier.VerifyMQConsumeAttributes(stubs[0][1], "", "", "", "process", topicName, "kafka")
+		verifier.VerifyMQConsumeAttributes(stubs[0][2], "", "", "", "process", topicName, "kafka")
+	}, 1)
+}
diff --git a/test/segmentio_kafka_go_tests.go b/test/segmentio_kafka_go_tests.go
new file mode 100644
index 000000000..8304559e8
--- /dev/null
+++ b/test/segmentio_kafka_go_tests.go
@@ -0,0 +1,153 @@
+package test
+
+import (
+	"context"
+	"fmt"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/go-connections/nat"
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/testcontainers/testcontainers-go/network"
+	"github.com/testcontainers/testcontainers-go/wait"
+	"net"
+	"testing"
+	"time"
+)
+
+const kafkaModuleName = "segmentio-kafka-go"
+
+func init() {
+	TestCases = append(TestCases,
+		NewGeneralTestCase("segmentio-kafka-go-basic-test", kafkaModuleName, "0.4.0", "", "1.18.0", "", TestBasicKafka),
+	)
+}
+
+func TestBasicKafka(t *testing.T, env ...string) {
+	containers := initKafkaContainer(t)
+	defer containers.CleanupContainers(context.Background())
+	UseApp("segmentio-kafka-go/v0.4.48")
+	RunGoBuild(t, "go", "build", "test_kafka_basic.go", "base.go")
+	env = append(env, "KAFKA_ADDR="+containers.KafkaAddress)
+	RunApp(t, "test_kafka_basic", env...)
+}
+
+// KafkaContainers encapsulates Kafka and Zookeeper containers for unified management
+type KafkaContainers struct {
+	ZookeeperContainer testcontainers.Container
+	KafkaContainer     testcontainers.Container
+	ZookeeperAddress   string
+	KafkaAddress       string
+	network            testcontainers.Network
+}
+
+// CleanupContainers Cleanup terminates all containers and network resources
+func (k *KafkaContainers) CleanupContainers(ctx context.Context) error {
+	var errs []error
+
+	if k.KafkaContainer != nil {
+		if err := k.KafkaContainer.Terminate(ctx); err != nil {
+			errs = append(errs, fmt.Errorf("failed to terminate Kafka container: %w", err))
+		}
+	}
+
+	if k.ZookeeperContainer != nil {
+		if err := k.ZookeeperContainer.Terminate(ctx); err != nil {
+			errs = append(errs, fmt.Errorf("failed to terminate Zookeeper container: %w", err))
+		}
+	}
+
+	if k.network != nil {
+		if err := k.network.Remove(ctx); err != nil {
+			errs = append(errs, fmt.Errorf("failed to remove network: %w", err))
+		}
+	}
+
+	if len(errs) > 0 {
+		return fmt.Errorf("cleanup errors: %v", errs)
+	}
+	return nil
+}
+
+// initKafkaContainer initializes a complete Kafka testing environment
+func initKafkaContainer(t *testing.T) *KafkaContainers {
+	ctx := context.Background()
+
+	// Create a dedicated network for the containers
+	testNetwork, err := network.New(ctx, network.WithCheckDuplicate())
+	if err != nil {
+		t.Fatalf("Failed to create test network: %v", err)
+	}
+
+	containers := &KafkaContainers{network: testNetwork}
+
+	// Start Zookeeper container
+	zookeeperReq := testcontainers.ContainerRequest{
+		Image:        "wurstmeister/zookeeper:latest",
+		ExposedPorts: []string{"2181/tcp"},
+		Env: map[string]string{
+			"ZOOKEEPER_CLIENT_PORT": "2181",
+		},
+		WaitingFor: wait.ForLog("binding to port").WithStartupTimeout(30 * time.Second),
+		Networks:   []string{testNetwork.Name},
+		NetworkAliases: map[string][]string{
+			testNetwork.Name: {"zookeeper"},
+		},
+	}
+
+	zookeeperC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
+		ContainerRequest: zookeeperReq,
+		Started:          true,
+	})
+	if err != nil {
+		t.Fatalf("Failed to start Zookeeper container: %v", err)
+	}
+
+	hostIP := "127.0.0.1" // For test environment access
+	zkAddr := net.JoinHostPort(hostIP, "2181")
+
+	// Start Kafka container
+	kafkaReq := testcontainers.ContainerRequest{
+		Image:        "wurstmeister/kafka:2.12-2.4.1",
+		ExposedPorts: []string{"9092/tcp"},
+		Env: map[string]string{
+			"KAFKA_ADVERTISED_LISTENERS":      fmt.Sprintf("PLAINTEXT://%s:9092", hostIP),
+			"KAFKA_LISTENERS":                 "PLAINTEXT://0.0.0.0:9092",
+			"KAFKA_ZOOKEEPER_CONNECT":         "zookeeper:2181",
+			"KAFKA_CREATE_TOPICS":             "test-topic:1:1",
+			"KAFKA_AUTO_CREATE_TOPICS_ENABLE": "true",
+		},
+		HostConfigModifier: func(hc *container.HostConfig) {
+			hc.PortBindings = nat.PortMap{
+				"9092/tcp": []nat.PortBinding{{
+					HostIP:   "0.0.0.0",
+					HostPort: "9092",
+				}},
+			}
+		},
+		WaitingFor: wait.ForLog("started (kafka.server.KafkaServer)").WithStartupTimeout(60 * time.Second),
+		Networks:   []string{testNetwork.Name},
+		NetworkAliases: map[string][]string{
+			testNetwork.Name: {"kafka"},
+		},
+	}
+
+	kafkaC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
+		ContainerRequest: kafkaReq,
+		Started:          true,
+	})
+	if err != nil {
+		_ = zookeeperC.Terminate(ctx)
+		t.Fatalf("Failed to start Kafka container: %v", err)
+	}
+
+	kafkaAddr := net.JoinHostPort(hostIP, "9092")
+
+	// Wait for Kafka to be fully ready
+	time.Sleep(5 * time.Second)
+
+	containers.ZookeeperContainer = zookeeperC
+	containers.KafkaContainer = kafkaC
+	containers.ZookeeperAddress = zkAddr
+	containers.KafkaAddress = kafkaAddr
+
+	return containers
+}
diff --git a/tool/config/config.go b/tool/config/config.go
index 2c354255b..4abd456a3 100644
--- a/tool/config/config.go
+++ b/tool/config/config.go
@@ -58,10 +58,15 @@ type BuildConfig struct {
 	DisableDefault bool
 }
 
+// @@This value is specified by the build system.
 // This is the version of the tool, which will be printed when the -version flag
-// is passed. This value is specified by the build system.
+// is passed.
 var ToolVersion = "1.0.0"
 
+// @@This value is specified by the build system.
+// It specifies the source path of the tool, which will be used to find the rules
+var BuildPath = ""
+
 var conf *BuildConfig
 
 func GetConf() *BuildConfig {
diff --git a/tool/data/default.json b/tool/data/default.json
index f2ea6584c..336b4fea7 100644
--- a/tool/data/default.json
+++ b/tool/data/default.json
@@ -957,5 +957,23 @@
   "OnEnter": "clientStdioOnEnter",
   "OnExit":"clientStdioOnExit",
   "Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/mcp"
-}
+},
+  {
+    "Version": "[0.4.0,)",
+    "ImportPath": "github.com/segmentio/kafka-go",
+    "Function": "WriteMessages",
+    "ReceiverType": "\\*Writer",
+    "OnEnter": "producerWriteMessagesOnEnter",
+    "OnExit": "producerWriteMessagesOnExit",
+    "Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/segmentio-kafka-go"
+  },
+  {
+    "Version": "[0.4.0,)",
+    "ImportPath": "github.com/segmentio/kafka-go",
+    "Function": "ReadMessage",
+    "ReceiverType": "\\*Reader",
+    "OnEnter": "consumerReadMessageOnEnter",
+    "OnExit": "consumerReadMessageOnExit",
+    "Path": "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/rules/segmentio-kafka-go"
+  }
 ]
diff --git a/tool/preprocess/preprocess.go b/tool/preprocess/preprocess.go
index bd7e14ed9..572cce76c 100644
--- a/tool/preprocess/preprocess.go
+++ b/tool/preprocess/preprocess.go
@@ -207,8 +207,7 @@ func (dp *DepProcessor) initMod() (err error) {
 	// module, that's why we do this here.
 	// TODO: Once we publish the alibaba-otel/pkg module, we can remove this code
 	// along with the replace directive in the go.mod file.
-	pkgUrl := "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg@f55e1e8"
-	dp.pkgLocalCache, err = dp.findModCacheDir(pkgUrl)
+	dp.pkgLocalCache, err = dp.findModCacheDir()
 	if err != nil {
 		return err
 	}
diff --git a/tool/preprocess/rectify.go b/tool/preprocess/rectify.go
index f92ccc927..876f0be1d 100644
--- a/tool/preprocess/rectify.go
+++ b/tool/preprocess/rectify.go
@@ -20,6 +20,7 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/config"
 	"github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/errc"
 	"github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/util"
 )
@@ -34,7 +35,19 @@ type moduleInfo struct {
 	Dir   string `json:"Dir"`
 }
 
-func (dp *DepProcessor) findModCacheDir(modulePath string) (string, error) {
+func (dp *DepProcessor) findModCacheDir() (string, error) {
+	if config.BuildPath != "" && util.PathExists(config.BuildPath) {
+		// In development mode, there is a high probability that we may have
+		// added new rules. In such cases, we prefer to use the pkg directory
+		// with the newly added rules rather than the remote pkg module. Our
+		// approach is to embed the source code directory into the tool during
+		// the packaging process. The tool will then check whether this directory
+		// exists. If it does exist, the tool will use it. Otherwise, we will
+		// fall back to using the remote pkg module.
+		return config.BuildPath, nil
+	}
+
+	modulePath := "github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg@f55e1e8"
 	output, err := runCmdCombinedOutput(dp.getGoModDir(),
 		"go", "mod", "download", "-json", modulePath)
 	if err != nil {


Reviews:
user: login: 123liuziming
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-18T08:25:36Z
user: login: 123liuziming
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-18T08:45:28Z
user: login: 123liuziming
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-18T08:51:52Z
user: login: 123liuziming
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-18T08:54:03Z
user: login: 123liuziming
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-18T08:56:33Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T02:07:43Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T02:22:16Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T02:22:21Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T02:22:26Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T02:22:37Z
user: login: Cirilla-zmh
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-20T03:35:53Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T01:58:33Z
user: login: DeepSeaCat
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T01:59:23Z
user: login: 123liuziming
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-21T06:00:27Z

Review comments:
diff_hunk: @@ -0,0 +1,60 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
+	"github.com/segmentio/kafka-go"
+	"time"
+)
+
+// github.com/segmentio/kafka-go/Reader.ReadMessage
+func consumerReadMessageOnEnter(call api.CallContext, _ interface{}, ctx context.Context) {
+	if !kafkaEnabler.Enable() {
+		return
+	}
+
+	instrumentationData := map[string]interface{}{
+		"originalContext": ctx,
path: pkg/rules/kafka-go/kafka_consumer_setup.go
user: login: 123liuziming
body: originalContext is better to be named as parentContext
created_at: 2025-05-18T08:25:36Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,322 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = instrumenter.NewDefaultInstrumentEnabler()
path: pkg/rules/kafka-go/kafka_otel_instrumenter.go
user: login: 123liuziming
body: You can read an environment variable like `SEGMENTIO_KAFKA_ENABLE` (default value is true) in kafkaEnabler.
created_at: 2025-05-18T08:45:28Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,322 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = instrumenter.NewDefaultInstrumentEnabler()
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
+	return int64(4 + 1 + 1 + 4 + len(request.msg.Key) + 4 + len(request.msg.Value) + 8)
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageEnvelopSize(request kafkaConsumerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageId(request kafkaConsumerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetClientId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetBatchMessageCount(request kafkaConsumerReq, response any) int64 {
+	return 1
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageHeader(request kafkaConsumerReq, name string) []string {
+	if request.msg.Headers == nil {
+		return nil
+	}
+	var headerValues []string
+	for _, header := range request.msg.Headers {
+		if header.Key == name {
+			headerValues = append(headerValues, string(header.Value))
+		}
+	}
+	return headerValues
+}
+
+// KafkaProducerAttributesExtractor extracts producer attributes
+type kafkaProducerAttributesExtractor struct {
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnStart(attributes []attribute.KeyValue, parentContext context.Context, request kafkaProducerReq) ([]attribute.KeyValue, context.Context) {
+	kafkaAttributes := []attribute.KeyValue{
+		semconv.MessagingSystemKafka,
+		semconv.MessagingDestinationNameKey.String(request.topic),
+		semconv.MessagingOperationName("publish"),
+	}
+	return append(attributes, kafkaAttributes...), parentContext
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnEnd(attributes []attribute.KeyValue, ctx context.Context, request kafkaProducerReq, response any, err error) ([]attribute.KeyValue, context.Context) {
+	if err != nil {
path: pkg/rules/kafka-go/kafka_otel_instrumenter.go
user: login: 123liuziming
body: Error is already recored in the status of span, should we remove them here?
created_at: 2025-05-18T08:51:52Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,322 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = instrumenter.NewDefaultInstrumentEnabler()
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
+	return int64(4 + 1 + 1 + 4 + len(request.msg.Key) + 4 + len(request.msg.Value) + 8)
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageEnvelopSize(request kafkaConsumerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageId(request kafkaConsumerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetClientId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetBatchMessageCount(request kafkaConsumerReq, response any) int64 {
+	return 1
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageHeader(request kafkaConsumerReq, name string) []string {
+	if request.msg.Headers == nil {
+		return nil
+	}
+	var headerValues []string
+	for _, header := range request.msg.Headers {
+		if header.Key == name {
+			headerValues = append(headerValues, string(header.Value))
+		}
+	}
+	return headerValues
+}
+
+// KafkaProducerAttributesExtractor extracts producer attributes
+type kafkaProducerAttributesExtractor struct {
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnStart(attributes []attribute.KeyValue, parentContext context.Context, request kafkaProducerReq) ([]attribute.KeyValue, context.Context) {
+	kafkaAttributes := []attribute.KeyValue{
+		semconv.MessagingSystemKafka,
+		semconv.MessagingDestinationNameKey.String(request.topic),
+		semconv.MessagingOperationName("publish"),
+	}
+	return append(attributes, kafkaAttributes...), parentContext
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnEnd(attributes []attribute.KeyValue, ctx context.Context, request kafkaProducerReq, response any, err error) ([]attribute.KeyValue, context.Context) {
+	if err != nil {
+		attributes = append(attributes, attribute.String("error", err.Error()))
+	}
+	attributes = append(attributes, attribute.Bool("messaging.kafka.async", request.async))
+	attributes = append(attributes, attribute.String("messaging.kafka.broker_address", request.addr.String()))
path: pkg/rules/kafka-go/kafka_otel_instrumenter.go
user: login: 123liuziming
body: As far as I know, OpenTelemetry Kafka does not have those attributes in the latest spec(https://opentelemetry.io/docs/specs/semconv/messaging/kafka/). Do you follow the old semconv or just add those attributes by yourself?
created_at: 2025-05-18T08:54:03Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,153 @@
+package test
+
+import (
+	"context"
+	"fmt"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/go-connections/nat"
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/testcontainers/testcontainers-go/network"
+	"github.com/testcontainers/testcontainers-go/wait"
+	"net"
+	"testing"
+	"time"
+)
+
+const kafkaModuleName = "kafka-go"
+
+func init() {
+	TestCases = append(TestCases,
path: test/kafka-go_tests.go
user: login: 123liuziming
body: You can rename the test file as `segmentio_kafka_go_tests.go` because there may be other kafka libraries need to be instrumented in the future(such as IBM Sarama and etc)
created_at: 2025-05-18T08:56:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,322 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = instrumenter.NewDefaultInstrumentEnabler()
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
+	return int64(4 + 1 + 1 + 4 + len(request.msg.Key) + 4 + len(request.msg.Value) + 8)
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageEnvelopSize(request kafkaConsumerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageId(request kafkaConsumerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetClientId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetBatchMessageCount(request kafkaConsumerReq, response any) int64 {
+	return 1
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageHeader(request kafkaConsumerReq, name string) []string {
+	if request.msg.Headers == nil {
+		return nil
+	}
+	var headerValues []string
+	for _, header := range request.msg.Headers {
+		if header.Key == name {
+			headerValues = append(headerValues, string(header.Value))
+		}
+	}
+	return headerValues
+}
+
+// KafkaProducerAttributesExtractor extracts producer attributes
+type kafkaProducerAttributesExtractor struct {
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnStart(attributes []attribute.KeyValue, parentContext context.Context, request kafkaProducerReq) ([]attribute.KeyValue, context.Context) {
+	kafkaAttributes := []attribute.KeyValue{
+		semconv.MessagingSystemKafka,
+		semconv.MessagingDestinationNameKey.String(request.topic),
+		semconv.MessagingOperationName("publish"),
+	}
+	return append(attributes, kafkaAttributes...), parentContext
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnEnd(attributes []attribute.KeyValue, ctx context.Context, request kafkaProducerReq, response any, err error) ([]attribute.KeyValue, context.Context) {
+	if err != nil {
+		attributes = append(attributes, attribute.String("error", err.Error()))
+	}
+	attributes = append(attributes, attribute.Bool("messaging.kafka.async", request.async))
+	attributes = append(attributes, attribute.String("messaging.kafka.broker_address", request.addr.String()))
path: pkg/rules/kafka-go/kafka_otel_instrumenter.go
user: login: DeepSeaCat
body: In the source code of `segmentio/kafka-go`, the instrumentation points are asynchronous, so it's not possible to capture errors synchronously. Therefore, I added some custom attributes to quickly locate issues.

created_at: 2025-05-19T02:07:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
+	"github.com/segmentio/kafka-go"
+	"time"
+)
+
+// github.com/segmentio/kafka-go/Reader.ReadMessage
+func consumerReadMessageOnEnter(call api.CallContext, _ interface{}, ctx context.Context) {
+	if !kafkaEnabler.Enable() {
+		return
+	}
+
+	instrumentationData := map[string]interface{}{
+		"originalContext": ctx,
path: pkg/rules/kafka-go/kafka_consumer_setup.go
user: login: DeepSeaCat
body: ok
created_at: 2025-05-19T02:22:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,322 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = instrumenter.NewDefaultInstrumentEnabler()
path: pkg/rules/kafka-go/kafka_otel_instrumenter.go
user: login: DeepSeaCat
body: ok
created_at: 2025-05-19T02:22:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,322 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = instrumenter.NewDefaultInstrumentEnabler()
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
+	return int64(4 + 1 + 1 + 4 + len(request.msg.Key) + 4 + len(request.msg.Value) + 8)
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageEnvelopSize(request kafkaConsumerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageId(request kafkaConsumerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetClientId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetBatchMessageCount(request kafkaConsumerReq, response any) int64 {
+	return 1
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageHeader(request kafkaConsumerReq, name string) []string {
+	if request.msg.Headers == nil {
+		return nil
+	}
+	var headerValues []string
+	for _, header := range request.msg.Headers {
+		if header.Key == name {
+			headerValues = append(headerValues, string(header.Value))
+		}
+	}
+	return headerValues
+}
+
+// KafkaProducerAttributesExtractor extracts producer attributes
+type kafkaProducerAttributesExtractor struct {
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnStart(attributes []attribute.KeyValue, parentContext context.Context, request kafkaProducerReq) ([]attribute.KeyValue, context.Context) {
+	kafkaAttributes := []attribute.KeyValue{
+		semconv.MessagingSystemKafka,
+		semconv.MessagingDestinationNameKey.String(request.topic),
+		semconv.MessagingOperationName("publish"),
+	}
+	return append(attributes, kafkaAttributes...), parentContext
+}
+
+func (extractor *kafkaProducerAttributesExtractor) OnEnd(attributes []attribute.KeyValue, ctx context.Context, request kafkaProducerReq, response any, err error) ([]attribute.KeyValue, context.Context) {
+	if err != nil {
path: pkg/rules/kafka-go/kafka_otel_instrumenter.go
user: login: DeepSeaCat
body: ok
created_at: 2025-05-19T02:22:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+package test
+
+import (
+	"context"
+	"fmt"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/go-connections/nat"
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/testcontainers/testcontainers-go/network"
+	"github.com/testcontainers/testcontainers-go/wait"
+	"net"
+	"testing"
+	"time"
+)
+
+const kafkaModuleName = "kafka-go"
+
+func init() {
+	TestCases = append(TestCases,
path: test/kafka-go_tests.go
user: login: DeepSeaCat
body: ok
created_at: 2025-05-19T02:22:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,323 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+	"os"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = kafkaInnerEnabler{os.Getenv("OTEL_SEGMENTIO_KAFKA_ENABLED") != "false"}
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+type kafkaInnerEnabler struct {
+	enabled bool
+}
+
+func (k kafkaInnerEnabler) Enable() bool {
+	return k.enabled
+}
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
path: pkg/rules/segmentio-kafka-go/kafka_otel_instrumenter.go
user: login: Cirilla-zmh
body: Could you please add the reference of this calculation formula in your comment? In fact, I don't think it's a right way to calculate the body size, according to [the document of kafka](https://kafka.apache.org/documentation/#record).
created_at: 2025-05-20T03:35:40Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,323 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+	"os"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = kafkaInnerEnabler{os.Getenv("OTEL_SEGMENTIO_KAFKA_ENABLED") != "false"}
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+type kafkaInnerEnabler struct {
+	enabled bool
+}
+
+func (k kafkaInnerEnabler) Enable() bool {
+	return k.enabled
+}
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
path: pkg/rules/segmentio-kafka-go/kafka_otel_instrumenter.go
user: login: DeepSeaCat
body: https://github.com/segmentio/kafka-go/blob/af1725fb4fc0d856653afb2aeaeaa3cbfea18aec/message.go#L48
created_at: 2025-05-21T01:58:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,323 @@
+// Copyright (c) 2025 Alibaba Group Holding Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kafka
+
+import (
+	"context"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/message"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
+	"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
+	"github.com/segmentio/kafka-go"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/codes"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/sdk/instrumentation"
+	semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
+	"go.opentelemetry.io/otel/trace"
+	"os"
+)
+
+// Instrumentation enabler controller
+var kafkaEnabler = kafkaInnerEnabler{os.Getenv("OTEL_SEGMENTIO_KAFKA_ENABLED") != "false"}
+
+// Cache Instrumenter instances to avoid repeated creation
+var (
+	producerInstrumenter = buildKafkaProducerInstrumenter()
+	consumerInstrumenter = buildKafkaConsumerInstrumenter()
+)
+
+type kafkaInnerEnabler struct {
+	enabled bool
+}
+
+func (k kafkaInnerEnabler) Enable() bool {
+	return k.enabled
+}
+
+// KafkaProducerCarrier implements OpenTelemetry propagator carrier interface for producers
+type kafkaProducerCarrier struct {
+	messages []*kafka.Message
+}
+
+func (carrier kafkaProducerCarrier) Get(key string) string {
+	return ""
+}
+
+func (carrier kafkaProducerCarrier) Set(key, value string) {
+	for _, message := range carrier.messages {
+		message.Headers = append(message.Headers, kafka.Header{
+			Key:   key,
+			Value: []byte(value),
+		})
+	}
+}
+
+func (carrier kafkaProducerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaConsumerCarrier implements OpenTelemetry propagator carrier interface for consumers
+type kafkaConsumerCarrier struct {
+	message kafka.Message
+}
+
+func (carrier kafkaConsumerCarrier) Get(key string) string {
+	if carrier.message.Headers != nil {
+		for _, header := range carrier.message.Headers {
+			if header.Key == key {
+				return string(header.Value)
+			}
+		}
+	}
+	return ""
+}
+
+func (carrier kafkaConsumerCarrier) Set(key, value string) {
+	// Consumer carrier doesn't need to implement Set method
+}
+
+func (carrier kafkaConsumerCarrier) Keys() []string {
+	return []string{}
+}
+
+// KafkaProducerStatusExtractor extracts producer operation status
+type kafkaProducerStatusExtractor struct {
+}
+
+func (extractor *kafkaProducerStatusExtractor) Extract(span trace.Span, request kafkaProducerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaConsumerStatusExtractor extracts consumer operation status
+type kafkaConsumerStatusExtractor struct{}
+
+func (extractor *kafkaConsumerStatusExtractor) Extract(span trace.Span, request kafkaConsumerReq, response any, err error) {
+	if err != nil {
+		span.SetStatus(codes.Error, err.Error())
+	} else {
+		span.SetStatus(codes.Ok, "")
+	}
+}
+
+// KafkaMessageProducerAttributesGetter retrieves producer message attributes
+type kafkaMessageProducerAttrsGetter struct{}
+
+func (getter kafkaMessageProducerAttrsGetter) IsAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationPartitionId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetSystem(request kafkaProducerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestination(request kafkaProducerReq) string {
+	return request.topic
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetDestinationTemplate(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) IsTemporaryDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) isAnonymousDestination(request kafkaProducerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetConversationId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageBodySize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageEnvelopSize(request kafkaProducerReq) int64 {
+	return 0
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageId(request kafkaProducerReq, response any) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetClientId(request kafkaProducerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetBatchMessageCount(request kafkaProducerReq, response any) int64 {
+	return int64(len(request.msgs))
+}
+
+func (getter kafkaMessageProducerAttrsGetter) GetMessageHeader(request kafkaProducerReq, name string) []string {
+	return []string{}
+}
+
+// KafkaMessageConsumerAttributesGetter retrieves consumer message attributes
+type kafkaMessageConsumerAttrsGetter struct{}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationPartitionId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetSystem(request kafkaConsumerReq) string {
+	return "kafka"
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestination(request kafkaConsumerReq) string {
+	return request.msg.Topic
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetDestinationTemplate(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) IsTemporaryDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) isAnonymousDestination(request kafkaConsumerReq) bool {
+	return false
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetConversationId(request kafkaConsumerReq) string {
+	return ""
+}
+
+func (getter kafkaMessageConsumerAttrsGetter) GetMessageBodySize(request kafkaConsumerReq) int64 {
+	// Calculate message body size: 4(topic length) + 1(compression type) + 1(attributes) + 4(key length) + key length + 4(value length) + value length + 8(timestamp)
path: pkg/rules/segmentio-kafka-go/kafka_otel_instrumenter.go
user: login: DeepSeaCat
body: I calculated according to the calculation method given by this function, which may be wrong.
created_at: 2025-05-21T01:59:22Z
author_association: CONTRIBUTOR

PR comments:
user: login: 123liuziming
created_at: 2025-05-18T09:06:50Z
body: And this project has been refactored in #362 by using `go:linkname`, and you may not need to write rules in `default.json` now, you just need to add something like `//go:linkname consumeOnEnter github.com/rabbitmq/amqp091-go.consumeOnEnter` before your `onEnter` function(e.g https://github.com/alibaba/opentelemetry-go-auto-instrumentation/blob/main/pkg/rules/amqp091/consume_setup.go).  cc@y1yang0 
author_association: COLLABORATOR
user: login: DeepSeaCat
created_at: 2025-05-19T02:23:11Z
body: > And this project has been refactored in #362 by using `go:linkname`, and you may not need to write rules in `default.json` now, you just need to add something like `//go:linkname consumeOnEnter github.com/rabbitmq/amqp091-go.consumeOnEnter` before your `onEnter` function(e.g https://github.com/alibaba/opentelemetry-go-auto-instrumentation/blob/main/pkg/rules/amqp091/consume_setup.go). cc@y1yang0

ok,I will rejoin the latest main
author_association: CONTRIBUTOR
user: login: y1yang0
created_at: 2025-05-20T01:59:19Z
body: I guess the failure is irreverent to this patch, I'll fix it.

@123liuziming @NameHaibinZhang @Cirilla-zmh Please help review the hook code. You can ignore the test failures. Thanks.
author_association: MEMBER
user: login: 123liuziming
created_at: 2025-05-20T02:13:14Z
body: > I guess the failure is irreverent to this patch, I'll fix it.
> 
> @123liuziming @NameHaibinZhang @Cirilla-zmh Please help review the hook code. You can ignore the test failures. Thanks.

I've reviewed the hook code, the test failure is about the change of `go:linkname`. New plugins rules can not be found in current implementation. 
author_association: COLLABORATOR
user: login: y1yang0
created_at: 2025-05-20T06:48:43Z
body: Could you try cherry-picking this commit https://github.com/alibaba/opentelemetry-go-auto-instrumentation/commit/bd486bbf907a2954f16d29e27e546a87728f7290 to verify if it works? Thanks
author_association: MEMBER
user: login: DeepSeaCat
created_at: 2025-05-21T02:30:22Z
body: > Could you try cherry-picking this commit [bd486bb](https://github.com/alibaba/opentelemetry-go-auto-instrumentation/commit/bd486bbf907a2954f16d29e27e546a87728f7290) to verify if it works? Thanks

My local verification is OK
author_association: CONTRIBUTOR