This is an automated email from the ASF dual-hosted git repository.
liuhan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-go.git
The following commit(s) were added to refs/heads/main by this push:
new a424bfc feat(add trace profile for go agent) (#229)
a424bfc is described below
commit a424bfc5615c7365e097c619955d7fefb93a9cce
Author: hao <[email protected]>
AuthorDate: Fri Oct 17 08:34:10 2025 +0800
feat(add trace profile for go agent) (#229)
---
agent/core/compile.go | 3 +
agent/core/{ => profile}/compile.go | 32 +-
agent/reporter/imports.go | 6 +-
go.work | 3 +
plugins/core/go.sum | 213 +++++--------
plugins/core/operator/common.go | 1 +
plugins/core/operator/profiler.go | 23 ++
plugins/core/prof_labels.go | 221 ++++++++++++++
plugins/core/prof_labels_test.go | 49 +++
plugins/core/profile.go | 336 +++++++++++++++++++++
plugins/core/profile/api.go | 33 ++
plugins/core/profile_event_manager.go | 58 ++++
plugins/core/profile_event_manager_test.go | 30 ++
plugins/core/profile_writer.go | 83 +++++
plugins/core/reporter/api.go | 10 +
plugins/core/reporter/discard_reporter.go | 3 +
plugins/core/reporter/grpc/grpc.go | 171 +++++++++--
plugins/core/reporter/kafka/kafka.go | 2 +
plugins/core/reporter/profile.go | 53 ++++
plugins/core/span.go | 1 +
plugins/core/span_default.go | 9 +
plugins/core/span_noop.go | 4 +
plugins/core/span_tracing.go | 12 +
plugins/core/test_base.go | 5 +
plugins/core/trace_profiling_event_manager.go | 165 ++++++++++
plugins/core/tracer.go | 7 +-
plugins/core/tracing.go | 32 ++
plugins/core/tracing/api.go | 1 +
plugins/core/tracing/bridge.go | 5 +
plugins/core/tracing/span.go | 2 +
plugins/echov4/intercepter.go | 1 -
plugins/http/server_intercepter.go | 1 -
plugins/pprof/go.mod | 3 +
plugins/pprof/instrument.go | 64 ++++
plugins/pprof/intercepter.go | 52 ++++
test/benchmark-codebase/consumer/main.go | 2 +-
test/e2e/case/kafka/docker-compose.yml | 4 +-
.../runner-helper/templates/docker-compose.tpl | 2 +-
.../templates/windows-docker-compose.tpl | 2 +-
test/plugins/scenarios/logrus/config/excepted.yml | 19 +-
.../plugin.yml => pprof/bin/startup.sh} | 30 +-
test/plugins/scenarios/pprof/config/excepted.yml | 114 +++++++
test/plugins/scenarios/pprof/go.mod | 3 +
test/plugins/scenarios/pprof/main.go | 96 ++++++
.../{segmentio-kafka => pprof}/plugin.yml | 68 ++---
test/plugins/scenarios/segmentio-kafka/plugin.yml | 2 +-
test/plugins/scenarios/zap/config/excepted.yml | 21 +-
tools/go-agent/config/agent.default.yaml | 3 +-
tools/go-agent/config/loader.go | 13 +-
tools/go-agent/instrument/agentcore/instrument.go | 2 +-
tools/go-agent/instrument/plugins/register.go | 2 +
.../go-agent/instrument/plugins/rewrite/context.go | 2 +-
tools/go-agent/instrument/plugins/rewrite/func.go | 6 +-
tools/go-agent/instrument/reporter/instrument.go | 10 +-
tools/go-agent/tools/dst.go | 2 +
55 files changed, 1813 insertions(+), 284 deletions(-)
diff --git a/agent/core/compile.go b/agent/core/compile.go
index baefdb1..16ca286 100644
--- a/agent/core/compile.go
+++ b/agent/core/compile.go
@@ -20,6 +20,7 @@ package core
import (
//go:nolint
_ "bytes"
+ _ "context"
_ "encoding/base64"
_ "fmt"
_ "io"
@@ -30,6 +31,7 @@ import (
_ "os"
_ "path/filepath"
_ "reflect"
+ _ "regexp"
_ "runtime"
_ "runtime/debug"
_ "runtime/metrics"
@@ -45,6 +47,7 @@ import (
//go:nolint
_ "github.com/apache/skywalking-go/agent/core/metrics"
_ "github.com/apache/skywalking-go/agent/core/operator"
+ _ "github.com/apache/skywalking-go/agent/core/profile"
_ "github.com/apache/skywalking-go/agent/core/tracing"
_ "github.com/apache/skywalking-go/agent/reporter"
_ "github.com/apache/skywalking-go/log"
diff --git a/agent/core/compile.go b/agent/core/profile/compile.go
similarity index 59%
copy from agent/core/compile.go
copy to agent/core/profile/compile.go
index baefdb1..97f8b11 100644
--- a/agent/core/compile.go
+++ b/agent/core/profile/compile.go
@@ -15,26 +15,14 @@
// specific language governing permissions and limitations
// under the License.
-package core
+package profile
import (
//go:nolint
_ "bytes"
- _ "encoding/base64"
+ _ "context"
_ "fmt"
- _ "io"
- _ "log"
- _ "math"
- _ "math/rand"
- _ "net"
- _ "os"
- _ "path/filepath"
- _ "reflect"
- _ "runtime"
- _ "runtime/debug"
- _ "runtime/metrics"
_ "runtime/pprof"
- _ "sort"
_ "strconv"
_ "strings"
_ "sync"
@@ -43,21 +31,11 @@ import (
_ "unsafe"
//go:nolint
- _ "github.com/apache/skywalking-go/agent/core/metrics"
- _ "github.com/apache/skywalking-go/agent/core/operator"
- _ "github.com/apache/skywalking-go/agent/core/tracing"
- _ "github.com/apache/skywalking-go/agent/reporter"
- _ "github.com/apache/skywalking-go/log"
+ _ "github.com/pkg/errors"
//go:nolint
- _ "github.com/google/uuid"
- _ "github.com/pkg/errors"
+ _ "github.com/apache/skywalking-go/agent/core/operator"
//go:nolint
- _ "github.com/apache/skywalking-go/protocols/collect/common/v3"
- _ "github.com/apache/skywalking-go/protocols/collect/event/v3"
- _ "github.com/apache/skywalking-go/protocols/collect/language/agent/v3"
- _
"github.com/apache/skywalking-go/protocols/collect/language/profile/v3"
- _ "github.com/apache/skywalking-go/protocols/collect/logging/v3"
- _ "github.com/apache/skywalking-go/protocols/collect/pprof/v10"
+ _ "github.com/apache/skywalking-go/agent/reporter"
)
diff --git a/agent/reporter/imports.go b/agent/reporter/imports.go
index 90c7e8a..34815e2 100644
--- a/agent/reporter/imports.go
+++ b/agent/reporter/imports.go
@@ -19,22 +19,26 @@ package reporter
import (
// imports required packages for gRPC reporter
+ _ "bytes"
_ "context"
_ "crypto/tls"
_ "crypto/x509"
_ "fmt"
_ "io"
_ "os"
+ _ "runtime"
+ _ "runtime/pprof"
_ "strconv"
_ "strings"
_ "sync"
_ "time"
- // imports the logs for reporter
+ // imports the logs and profiles for reporter
_ "github.com/apache/skywalking-go/agent/core/operator"
_ "github.com/apache/skywalking-go/log"
// imports configuration and starter for gRPC
+ _ "github.com/pkg/errors"
_ "google.golang.org/grpc"
_ "google.golang.org/grpc/backoff"
_ "google.golang.org/grpc/balancer"
diff --git a/go.work b/go.work
index 4afcbca..fc47bf5 100644
--- a/go.work
+++ b/go.work
@@ -26,6 +26,7 @@ use (
./plugins/rocketmq
./plugins/amqp
./plugins/pulsar
+ ./plugins/pprof
./plugins/segmentio-kafka
./plugins/go-elasticsearchv8
./plugins/goframe
@@ -72,8 +73,10 @@ use (
./test/plugins/scenarios/goframe
./test/plugins/scenarios/so11y
./test/plugins/scenarios/cross-goroutine
+ ./test/plugins/scenarios/pprof
./tools/go-agent
./toolkit
)
+
diff --git a/plugins/core/go.sum b/plugins/core/go.sum
index 2b06a84..f1c8167 100644
--- a/plugins/core/go.sum
+++ b/plugins/core/go.sum
@@ -1,58 +1,27 @@
-cloud.google.com/go v0.26.0/go.mod
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/BurntSushi/toml v0.3.1/go.mod
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/OneOfOne/xxhash v1.2.2/go.mod
h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/antihax/optional v1.0.0/go.mod
h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod
h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/client9/misspell v0.3.4/go.mod
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod
h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod
h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod
h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/creack/pty v1.1.9/go.mod
h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dave/dst v0.27.2 h1:4Y5VFTkhGLC1oddtNwuxxe36pnyLxMFXT51FOzH8Ekc=
github.com/dave/dst v0.27.2/go.mod
h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc=
+github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY=
+github.com/dave/dst v0.27.3/go.mod
h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc=
github.com/dave/jennifer v1.5.0 h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg=
+github.com/dave/jennifer v1.5.0/go.mod
h1:4MnyiFIlZS3l5tSDn8VnzE6ffAhYBMB2SZntBsZGUok=
github.com/davecgh/go-spew v1.1.0/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane
v0.9.9-0.20201210154907-fd9021fe5dad/go.mod
h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane
v0.9.9-0.20210217033140-668b12f5399d/go.mod
h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane
v0.9.9-0.20210512163311-63b5d3c536b0/go.mod
h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/ghodss/yaml v1.0.0/go.mod
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod
h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod
h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod
h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod
h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod
h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod
h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod
h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod
h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod
h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod
h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod
h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod
h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod
h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3
h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod
h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/go-cmp v0.2.0/go.mod
h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod
h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod
h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/uuid v1.1.2/go.mod
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod
h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod
h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod
h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/golang/protobuf v1.5.4
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/klauspost/compress v1.15.9
h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
+github.com/klauspost/compress v1.15.9/go.mod
h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
+github.com/klauspost/compress v1.15.15
h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
+github.com/klauspost/compress v1.15.15/go.mod
h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/kr/pretty v0.1.0/go.mod
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod
h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
@@ -61,144 +30,120 @@ github.com/kr/pty v1.1.1/go.mod
h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/pierrec/lz4/v4 v4.1.15
h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
+github.com/pierrec/lz4/v4 v4.1.15/go.mod
h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pierrec/lz4/v4 v4.1.22
h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
+github.com/pierrec/lz4/v4 v4.1.22/go.mod
h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod
h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod
h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.6.1/go.mod
h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.10.0
h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod
h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/segmentio/kafka-go v0.4.47
h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
+github.com/segmentio/kafka-go v0.4.47/go.mod
h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
+github.com/segmentio/kafka-go v0.4.49
h1:GJiNX1d/g+kG6ljyJEoi9++PUMdXGAxb7JGPiDCuNmk=
+github.com/segmentio/kafka-go v0.4.49/go.mod
h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod
h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/sergi/go-diff v1.2.0/go.mod
h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod
h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod
h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.5.1/go.mod
h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod
h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2
h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/yuin/goldmark v1.3.5/go.mod
h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/stretchr/testify v1.8.4
h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod
h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod
h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
+github.com/xdg-go/scram v1.1.2/go.mod
h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
+github.com/xdg-go/stringprep v1.0.4
h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
+github.com/xdg-go/stringprep v1.0.4/go.mod
h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/yuin/goldmark v1.4.13/go.mod
h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod
h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/auto/sdk v1.1.0
h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod
h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/otel v1.35.0
h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
+go.opentelemetry.io/otel v1.35.0/go.mod
h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/metric v1.35.0
h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
+go.opentelemetry.io/otel/metric v1.35.0/go.mod
h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
+go.opentelemetry.io/otel/sdk v1.35.0
h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
+go.opentelemetry.io/otel/sdk v1.35.0/go.mod
h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
+go.opentelemetry.io/otel/sdk/metric v1.35.0
h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
+go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod
h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
+go.opentelemetry.io/otel/trace v1.35.0
h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
+go.opentelemetry.io/otel/trace v1.35.0/go.mod
h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod
h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod
h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-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-20210508222113-6edffad5e616/go.mod
h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod
h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/crypto v0.14.0/go.mod
h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod
h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod
h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod
h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod
h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod
h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod
h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-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-20220520151302-bc2c85ada10a/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0/go.mod
h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod
h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod
h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-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-20190524140312-2c0ae7006135/go.mod
h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod
h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.1.3/go.mod
h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod
h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
+golang.org/x/tools v0.6.0/go.mod
h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod
h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0/go.mod
h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod
h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod
h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod
h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod
h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod
h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod
h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
-google.golang.org/grpc v1.19.0/go.mod
h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod
h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod
h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod
h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.1/go.mod
h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod
h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.38.0/go.mod
h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.40.0/go.mod
h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
-google.golang.org/grpc v1.55.0/go.mod
h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod
h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod
h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod
h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod
h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod
h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod
h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod
h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod
h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod
h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod
h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.29.0/go.mod
h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.30.0
h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod
h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1
h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA=
+google.golang.org/genproto/googleapis/rpc
v0.0.0-20250826171959-ef028d996bc1/go.mod
h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
+google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
+google.golang.org/grpc v1.73.0/go.mod
h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
+google.golang.org/protobuf v1.36.6
h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod
h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+google.golang.org/protobuf v1.36.8
h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod
h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-skywalking.apache.org/repo/goapi v0.0.0-20230314034821-0c5a44bb767a
h1:m8DTnaSEOEnPXRWmA6g7isbdqw7WPZP6SnaEHz1Sx7s=
-skywalking.apache.org/repo/goapi v0.0.0-20230314034821-0c5a44bb767a/go.mod
h1:LcZMcxDjdJPn5yetydFnxe0l7rmiv8lvHEnzRbsey14=
+skywalking.apache.org/repo/goapi v0.0.0-20250520033135-e237d585745f
h1:of4GHiflH8hS8uabPidaHvuruM8uyY5u78G83IDI1Fc=
+skywalking.apache.org/repo/goapi v0.0.0-20250520033135-e237d585745f/go.mod
h1:rTNGn2QrS+p1i2OaIBxlwQ/VrDSDc7OwRk/iWV+mU0k=
diff --git a/plugins/core/operator/common.go b/plugins/core/operator/common.go
index e53f006..0a4b60a 100644
--- a/plugins/core/operator/common.go
+++ b/plugins/core/operator/common.go
@@ -25,6 +25,7 @@ var MetricsCollectAppender = func(func()) {}
type Operator interface {
Tracing() interface{} // to TracingOperator
Logger() interface{} // to LogOperator
+ Profiler() interface{} // to ProfileOperator
Tools() interface{} // to ToolsOperator
DebugStack() []byte // Getting the stack of the current
goroutine, for getting details when plugin broken.
Entity() interface{} // Get the entity of the service
diff --git a/plugins/core/operator/profiler.go
b/plugins/core/operator/profiler.go
new file mode 100644
index 0000000..97b57bb
--- /dev/null
+++ b/plugins/core/operator/profiler.go
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 operator
+
+type ProfileOperator interface {
+ // GetNowLabels get skywalking internal labels from goroutine,avoid
covered by user
+ GetNowLabels() interface{}
+}
diff --git a/plugins/core/prof_labels.go b/plugins/core/prof_labels.go
new file mode 100644
index 0000000..b4a62f9
--- /dev/null
+++ b/plugins/core/prof_labels.go
@@ -0,0 +1,221 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+import (
+ "context"
+ "regexp"
+ "runtime"
+ "runtime/pprof"
+ "sort"
+ "strconv"
+ "unsafe"
+)
+
+type label struct {
+ key string
+ value string
+}
+
+type LabelSet struct {
+ list []label
+}
+
+type labelMap struct {
+ LabelSet
+}
+
+type labelMap19 map[string]string
+
+type labelContextKey struct{}
+
+//go:linkname runtimeGetProfLabel runtime/pprof.runtime_getProfLabel
+func runtimeGetProfLabel() unsafe.Pointer
+
+//go:linkname runtimeSetProfLabel runtime/pprof.runtime_setProfLabel
+func runtimeSetProfLabel(label unsafe.Pointer)
+
+func setGoroutineLabelsInternal(ctx context.Context) {
+ if isGoVersionLMoreThan120(runtime.Version()) {
+ ctxLabels, _ := ctx.Value(labelContextKey{}).(*labelMap)
+ runtimeSetProfLabel(unsafe.Pointer(ctxLabels))
+ return
+ }
+ ctxLabels, _ := ctx.Value(labelContextKey{}).(*labelMap19)
+ runtimeSetProfLabel(unsafe.Pointer(ctxLabels))
+}
+
+func labelValue(ctx context.Context) labelMap19 {
+ labels, _ := ctx.Value(labelContextKey{}).(*labelMap19)
+ if labels == nil {
+ return labelMap19(nil)
+ }
+ return *labels
+}
+
+func WithLabels(ctx context.Context, s LabelSet) context.Context {
+ if isGoVersionLMoreThan120(runtime.Version()) {
+ ctx = context.WithValue(ctx, labelContextKey{}, &labelMap{s})
+ return ctx
+ }
+ return withLabels19(ctx, s)
+}
+
+func withLabels19(ctx context.Context, labels LabelSet) context.Context {
+ childLabels := make(labelMap19)
+ parentLabels := labelValue(ctx)
+ for k, v := range parentLabels {
+ childLabels[k] = v
+ }
+ for _, label := range labels.list {
+ childLabels[label.key] = label.value
+ }
+ return context.WithValue(ctx, labelContextKey{}, &childLabels)
+}
+
+func GetNowLabelSet() LabelSet {
+ pl := LabelSet{
+ list: make([]label, 0),
+ }
+ p := runtimeGetProfLabel()
+ if p != nil {
+ version := runtime.Version()
+ if !isGoVersionLMoreThan120(version) {
+ // Go1.19:map[string]string -> []label
+ m := *(*labelMap19)(p)
+ pl.list = make([]label, 0, len(m))
+ for k, v := range m {
+ pl.list = append(pl.list, label{key: k, value:
v})
+ }
+ } else {
+ lm := (*labelMap)(p)
+ pl.list = lm.list
+ }
+ }
+ return pl
+}
+
+// isGoVersionLMoreThan120 parses version strings like "go1.19.8"
+func isGoVersionLMoreThan120(version string) bool {
+ re := regexp.MustCompile(`go(\d+)\.(\d+)`)
+ sub := re.FindStringSubmatch(version)
+ if len(sub) != 3 {
+ return false
+ }
+ major, err1 := strconv.Atoi(sub[1])
+ minor, err2 := strconv.Atoi(sub[2])
+ if err1 != nil || err2 != nil {
+ return false
+ }
+ if major < 1 {
+ return false
+ }
+ if major > 1 {
+ return true
+ }
+ return minor >= 20
+}
+
+func (m *ProfileManager) AddSkyLabels(traceID, segmentID string, spanID int32)
interface{} {
+ pl := GetNowLabelSet()
+ re := UpdateTraceLabels(pl, TraceLabel, traceID, SegmentLabel,
segmentID, SpanLabel, parseString(spanID))
+ return &re
+}
+
+func (m *ProfileManager) TurnToPprofLabel(l *LabelSet) pprof.LabelSet {
+ li := l.List()
+ if len(li) == 0 {
+ return pprof.LabelSet{}
+ }
+ re := pprof.Labels(li...)
+ return re
+}
+
+func UpdateTraceLabels(s LabelSet, args ...string) LabelSet {
+ if len(args)%2 != 0 {
+ panic("uneven number of arguments to profile.UpdateTraceLabels")
+ }
+
+ // add first
+ for i := 0; i < len(args); i += 2 {
+ s.list = append(s.list, label{key: args[i], value: args[i+1]})
+ }
+
+ // sort
+ sort.SliceStable(s.list, func(i, j int) bool {
+ return s.list[i].key < s.list[j].key
+ })
+
+ // remove duplicates
+ deduped := make([]label, 0, len(s.list))
+ for i, lbl := range s.list {
+ if i == 0 || lbl.key != s.list[i-1].key {
+ deduped = append(deduped, lbl)
+ } else {
+ deduped[len(deduped)-1] = lbl
+ }
+ }
+ s.list = deduped
+
+ return s
+}
+
+func (s *LabelSet) List() []string {
+ var ret []string
+ for _, v := range s.list {
+ ret = append(ret, v.key, v.value)
+ }
+ return ret
+}
+
+func SetGoroutineLabels(s *LabelSet) {
+ if s.IsEmpty() {
+ var c = context.Background()
+ setGoroutineLabelsInternal(c)
+ return
+ }
+ var c = context.Background()
+ l := *s
+ c = WithLabels(c, l)
+ setGoroutineLabelsInternal(c)
+}
+
+func extractSkyInternalLabels(s LabelSet) LabelSet {
+ re := LabelSet{list: make([]label, 0)}
+ for _, l := range s.list {
+ if l.key == SpanLabel || l.key == SegmentLabel || l.key ==
TraceLabel || l.key == MinDurationLabel {
+ re.list = append(re.list, l)
+ }
+ }
+ return re
+}
+
+// GetNowLabels Expose to operator
+func (m *ProfileManager) GetNowLabels() interface{} {
+ row := GetNowLabelSet()
+ filter := extractSkyInternalLabels(row)
+ re := m.TurnToPprofLabel(&filter)
+ return re
+}
+
+func (s *LabelSet) IsEmpty() bool {
+ if s == nil || s.list == nil {
+ return true
+ }
+ return len(s.list) == 0
+}
diff --git a/plugins/core/prof_labels_test.go b/plugins/core/prof_labels_test.go
new file mode 100644
index 0000000..a52f581
--- /dev/null
+++ b/plugins/core/prof_labels_test.go
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+import (
+ "sort"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func sortLabels(ls LabelSet) LabelSet {
+ sort.Slice(ls.list, func(i, j int) bool {
+ return ls.list[i].key < ls.list[j].key
+ })
+ return ls
+}
+
+func TestGetLabels(t *testing.T) {
+ p := NewProfileManager(nil)
+ p.currentTask = ¤tTask{
+ serialNumber: "",
+ taskID: "",
+ minDurationThreshold: 0,
+ endpointName: "",
+ duration: 0,
+ }
+ ls := p.AddSkyLabels("test-TraceID", "test-segmentID", 0).(*LabelSet)
+ ts := LabelSet{list: []label{
+ {key: "spanID", value: "0"},
+ {key: "traceSegmentID", value: "test-segmentID"},
+ {key: "traceID", value: "test-TraceID"}}}
+ assert.Equal(t, sortLabels(ts), sortLabels(*ls))
+}
diff --git a/plugins/core/profile.go b/plugins/core/profile.go
new file mode 100644
index 0000000..c8d8f68
--- /dev/null
+++ b/plugins/core/profile.go
@@ -0,0 +1,336 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+import (
+ "runtime/pprof"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/reporter"
+ common "github.com/apache/skywalking-go/protocols/collect/common/v3"
+)
+
+type profileLabels struct {
+ labels *LabelSet
+}
+
+const (
+ maxSendQueueSize int32 = 100
+ timeOut time.Duration = 2 * time.Minute
+ ChunkSize = 1024 * 1024
+ TraceLabel = "traceID"
+ SegmentLabel = "traceSegmentID"
+ MinDurationLabel = "minDurationThreshold"
+ SpanLabel = "spanID"
+)
+
+type currentTask struct {
+ serialNumber string // uuid
+ taskID string
+ minDurationThreshold int64
+ endpointName string
+ endTime time.Time
+ duration int
+}
+
+type ProfileManager struct {
+ mu sync.Mutex
+ TraceProfileTask *reporter.TraceProfileTask
+ ProfileTaskQueue []*reporter.TraceProfileTask
+ rawCh chan profileRawData
+ FinalReportResults chan reporter.ProfileResult
+ profilingWriter *ProfilingWriter
+ profileEvents *TraceProfilingEventManager
+ currentTask *currentTask
+ Log operator.LogOperator
+}
+
+func (m *ProfileManager) initReportChannel() {
+ // Original channel for receiving raw data chunks sent by the Writer
+ rawCh := make(chan profileRawData, maxSendQueueSize)
+ m.rawCh = rawCh
+ var d []byte
+ // Start a goroutine to supplement each data chunk with business
information
+ go func() {
+ for rawResult := range rawCh {
+ d = append(d, rawResult.data...)
+ m.mu.Lock()
+ // Get business information from currentTask
+ if m.currentTask == nil {
+ m.Log.Info("no task")
+ m.mu.Unlock()
+ continue // Task has ended, ignore
+ }
+ task := m.currentTask
+ m.mu.Unlock()
+
+ if rawResult.isLast {
+ m.FinalReportResults <- reporter.ProfileResult{
+ TaskID: task.taskID,
+ Payload: rawResult.data,
+ IsLast: rawResult.isLast,
+ }
+ m.mu.Lock()
+ if m.TraceProfileTask == nil {
+ m.Log.Warn("no TraceProfileTask before
finish profile")
+ } else {
+ m.TraceProfileTask.Status =
reporter.Finished
+ }
+ m.currentTask = nil
+ m.profileEvents.BaseEventStatus[CurTaskExist] =
false
+ m.mu.Unlock()
+ } else {
+ m.FinalReportResults <- reporter.ProfileResult{
+ TaskID: task.taskID,
+ Payload: rawResult.data,
+ IsLast: rawResult.isLast,
+ }
+ }
+ }
+ }()
+}
+
+func NewProfileManager(log operator.LogOperator) *ProfileManager {
+ pm := &ProfileManager{
+ FinalReportResults: make(chan reporter.ProfileResult,
maxSendQueueSize),
+ profileEvents: NewEventManager(),
+ ProfileTaskQueue: make([]*reporter.TraceProfileTask, 0),
+ }
+ pm.RegisterProfileEvents()
+
+ if log == nil {
+ log = newDefaultLogger()
+ }
+ pm.Log = log
+ pm.initReportChannel()
+ pm.profilingWriter = NewProfilingWriter(
+ ChunkSize,
+ pm.rawCh,
+ )
+ return pm
+}
+
+func (m *ProfileManager) AddProfileTask(args []*common.KeyStringValuePair, t
int64) int64 {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ var task reporter.TraceProfileTask
+ for _, arg := range args {
+ switch arg.Key {
+ case "TaskId":
+ task.TaskID = arg.Value
+ case "EndpointName":
+ task.EndpointName = arg.Value
+ case "Duration":
+ // Duration min
+ task.Duration = parseInt(arg.Value)
+ case "MinDurationThreshold":
+ task.MinDurationThreshold = parseInt64(arg.Value)
+ case "DumpPeriod":
+ task.DumpPeriod = parseInt(arg.Value)
+ case "MaxSamplingCount":
+ task.MaxSamplingCount = parseInt(arg.Value)
+ case "StartTime":
+ task.StartTime = time.UnixMilli(parseInt64(arg.Value))
+ case "CreateTime":
+ temp := parseInt64(arg.Value)
+ task.CreateTime = time.UnixMilli(temp)
+ if temp > t {
+ t = temp
+ }
+ case "SerialNumber":
+ task.SerialNumber = arg.Value
+ }
+ }
+ m.Log.Info("adding profile task:", task)
+ endTime := task.StartTime.Add(time.Duration(task.Duration) *
time.Minute)
+ task.EndTime = endTime
+ task.Status = reporter.Pending
+ m.addTask(&task)
+ return t
+}
+
+func (m *ProfileManager) RemoveProfileTask() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.TraceProfileTask == nil {
+ return
+ }
+ if m.TraceProfileTask.Status == reporter.Reported ||
+ time.Now().After(m.TraceProfileTask.EndTime.Add(timeOut)) {
+ m.TraceProfileTask = nil
+ }
+}
+
+func (m *ProfileManager) addTask(task *reporter.TraceProfileTask) {
+ if task == nil {
+ return
+ }
+ for _, t := range m.ProfileTaskQueue {
+ if task.EndTime.After(t.StartTime) &&
task.StartTime.Before(t.EndTime) {
+ return
+ }
+ }
+ m.ProfileTaskQueue = append(m.ProfileTaskQueue, task)
+
+ delay := time.Until(task.StartTime)
+ if delay < 0 {
+ delay = 0
+ }
+
+ time.AfterFunc(delay, func() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.TraceProfileTask != nil {
+ return
+ }
+ m.TraceProfileTask = task
+ m.trySetCurrentTaskAndStartProfile(task)
+ })
+}
+
+func (m *ProfileManager) tryStartCPUProfiling() {
+ ok, err := m.profileEvents.ExecuteComplexEvent(CouldProfile)
+ if err != nil {
+ m.Log.Errorf("profile event error:%v", err)
+ return
+ }
+ t := m.TraceProfileTask
+ if ok && t.Status == reporter.Pending {
+ err := pprof.StartCPUProfile(m.profilingWriter)
+ if err != nil {
+ m.Log.Info("failed to start cpu profiling", err)
+ return
+ }
+ err = m.profileEvents.UpdateBaseEventStatus(IfProfiling, true)
+ if err != nil {
+ m.Log.Errorf("update profile event error:%v", err)
+ }
+ t.Status = reporter.Running
+ go m.monitor()
+ }
+}
+
+func (m *ProfileManager) CheckIfProfileTarget(endpoint string) bool {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.currentTask == nil {
+ return false
+ }
+ return m.currentTask.endpointName == endpoint
+}
+
+func (m *ProfileManager) IfProfiling() bool {
+ ok, err := m.profileEvents.GetBaseEventStatus(IfProfiling)
+ if err != nil {
+ m.Log.Errorf("get profile event error:%v", err)
+ return false
+ }
+ return ok
+}
+
+func (m *ProfileManager) trySetCurrentTaskAndStartProfile(task
*reporter.TraceProfileTask) {
+ if m.currentTask != nil &&
time.Now().Before(m.currentTask.endTime.Add(timeOut)) {
+ return
+ }
+ ok, err := m.profileEvents.ExecuteComplexEvent(CouldSetCurTask)
+ if err != nil {
+ m.Log.Errorf("profile event error:%v", err)
+ }
+ if ok {
+ m.generateCurrentTask(task)
+ m.tryStartCPUProfiling()
+ }
+}
+
+func (m *ProfileManager) generateProfileLabels(traceSegmentID string,
minDurationThreshold int64) profileLabels {
+ var l = LabelSet{}
+ l = UpdateTraceLabels(l, SegmentLabel, traceSegmentID,
MinDurationLabel, strconv.FormatInt(minDurationThreshold, 10))
+ return profileLabels{
+ labels: &l,
+ }
+}
+
+func (m *ProfileManager) generateCurrentTask(t *reporter.TraceProfileTask) {
+ var c = currentTask{
+ serialNumber: t.SerialNumber,
+ taskID: t.TaskID,
+ minDurationThreshold: t.MinDurationThreshold,
+ duration: t.Duration,
+ endpointName: t.EndpointName,
+ endTime: t.EndTime,
+ }
+ m.currentTask = &c
+ err := m.profileEvents.UpdateBaseEventStatus(CurTaskExist, true)
+ if err != nil {
+ m.Log.Errorf("profile event error:%v", err)
+ }
+}
+
+func (m *ProfileManager) TryToAddSegmentLabelSet(traceSegmentID string) {
+ if m.currentTask != nil {
+ c := m.generateProfileLabels(traceSegmentID,
m.currentTask.minDurationThreshold)
+ SetGoroutineLabels(c.labels)
+ return
+ }
+}
+
+func (m *ProfileManager) monitor() {
+ <-time.After(time.Duration(m.currentTask.duration) * time.Minute)
+ pprof.StopCPUProfile()
+ err := m.profileEvents.UpdateBaseEventStatus(IfProfiling, false)
+ if err != nil {
+ m.Log.Errorf("profile event error:%v", err)
+ }
+ if m.profilingWriter != nil {
+ m.profilingWriter.Flush()
+ }
+}
+
+func (m *ProfileManager) AddSpanID(traceID, segmentID string, spanID int32) {
+ l := m.AddSkyLabels(traceID, segmentID, spanID).(*LabelSet)
+ SetGoroutineLabels(l)
+}
+
+func (m *ProfileManager) GetProfileResults() chan reporter.ProfileResult {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.FinalReportResults
+}
+
+func (m *ProfileManager) ProfileFinish() {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.TraceProfileTask.Status = reporter.Reported
+}
+
+func parseInt64(value string) int64 {
+ v, _ := strconv.ParseInt(value, 10, 64)
+ return v
+}
+
+func parseInt(value string) int {
+ v, _ := strconv.Atoi(value)
+ return v
+}
+func parseString(value int32) string {
+ str := strconv.Itoa(int(value))
+ return str
+}
diff --git a/plugins/core/profile/api.go b/plugins/core/profile/api.go
new file mode 100644
index 0000000..5a2b576
--- /dev/null
+++ b/plugins/core/profile/api.go
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 profile
+
+import "github.com/apache/skywalking-go/plugins/core/operator"
+
+func CatchNowProfileLabel() interface{} {
+ op := operator.GetOperator()
+ if op == nil {
+ return nil
+ }
+ profiler, ok := op.Profiler().(operator.ProfileOperator)
+ if !ok {
+ return nil
+ }
+ re := profiler.GetNowLabels()
+ return re
+}
diff --git a/plugins/core/profile_event_manager.go
b/plugins/core/profile_event_manager.go
new file mode 100644
index 0000000..ccd2547
--- /dev/null
+++ b/plugins/core/profile_event_manager.go
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+const (
+ IfProfiling TraceProfilingBaseEvent = "IfProfiling"
+ CurTaskExist TraceProfilingBaseEvent = "CurTaskExist"
+
+ CouldProfile TraceProfilingComplexEvent = "CouldProfile"
+ CouldSetCurTask TraceProfilingComplexEvent = "CouldSetCurTask"
+)
+
+func (m *ProfileManager) RegisterProfileEvents() {
+ m.profileEvents.RegisterBaseEvent(IfProfiling, false)
+ m.profileEvents.RegisterBaseEvent(CurTaskExist, false)
+ var r1 = TraceProfilingRule{
+ Event: IfProfiling,
+ Op: OpNothing,
+ IsNot: true,
+ }
+ var r2 = TraceProfilingRule{
+ Event: CurTaskExist,
+ Op: OpAnd,
+ IsNot: false,
+ }
+ var r3 = TraceProfilingRule{
+ Event: CurTaskExist,
+ Op: OpAnd,
+ IsNot: true,
+ }
+ m.profileEvents.RegisterComplexEvent(CouldProfile,
&TraceProfilingExprNode{
+ Rules: []TraceProfilingRule{
+ r1, r2,
+ },
+ Event: CouldProfile,
+ })
+ m.profileEvents.RegisterComplexEvent(CouldSetCurTask,
&TraceProfilingExprNode{
+ Rules: []TraceProfilingRule{
+ r1, r3,
+ },
+ Event: CouldSetCurTask,
+ })
+}
diff --git a/plugins/core/profile_event_manager_test.go
b/plugins/core/profile_event_manager_test.go
new file mode 100644
index 0000000..2f5dc8a
--- /dev/null
+++ b/plugins/core/profile_event_manager_test.go
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestProfileEventController(t *testing.T) {
+ m := NewProfileManager(nil)
+ re, _ := m.profileEvents.ExecuteComplexEvent(CouldProfile)
+ assert.Equal(t, false, re)
+}
diff --git a/plugins/core/profile_writer.go b/plugins/core/profile_writer.go
new file mode 100644
index 0000000..61d27de
--- /dev/null
+++ b/plugins/core/profile_writer.go
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+import (
+ "sync"
+)
+
+type ProfilingWriter struct {
+ mu sync.Mutex // Ensures concurrent safety
+ buf []byte // Temporary buffer for current chunk
+ chunkSize int // Threshold size for chunking (e.g.,
1MB)
+ reportCh chan<- profileRawData // Channel for sending data chunks
+}
+
+type profileRawData struct {
+ data []byte
+ isLast bool
+}
+
+// NewProfilingWriter initializes a ProfilingWriter with specified chunk size
and report channel
+func NewProfilingWriter(chunkSize int, reportCh chan<- profileRawData)
*ProfilingWriter {
+ return &ProfilingWriter{
+ chunkSize: chunkSize,
+ reportCh: reportCh,
+ buf: make([]byte, 0, chunkSize), // Preallocate buffer
for efficiency
+ }
+}
+
+// Write implements io.Writer, handles data chunking and sending
+func (w *ProfilingWriter) Write(p []byte) (n int, err error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ w.buf = append(w.buf, p...)
+
+ // Send chunks when buffer reaches the threshold
+ for len(w.buf) >= w.chunkSize {
+ chunk := w.buf[:w.chunkSize]
+ w.buf = w.buf[w.chunkSize:]
+
+ // Send raw chunk data (business info added externally)
+ w.reportCh <- profileRawData{
+ data: chunk,
+ isLast: false,
+ }
+ }
+
+ return len(p), nil
+}
+
+// Flush sends remaining data in the buffer
+func (w *ProfilingWriter) Flush() {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+
+ if len(w.buf) > 0 {
+ w.reportCh <- profileRawData{
+ data: w.buf,
+ isLast: true,
+ }
+ } else {
+ w.reportCh <- profileRawData{
+ data: nil,
+ isLast: true,
+ }
+ }
+ w.buf = nil
+}
diff --git a/plugins/core/reporter/api.go b/plugins/core/reporter/api.go
index 1d35b75..5d75fa8 100644
--- a/plugins/core/reporter/api.go
+++ b/plugins/core/reporter/api.go
@@ -108,11 +108,21 @@ var (
ConnectionStatusShutdown ConnectionStatus = 3
)
+type ProfileTaskStatus int
+
+const (
+ Pending ProfileTaskStatus = iota
+ Running
+ Finished
+ Reported
+)
+
type Reporter interface {
Boot(entity *Entity, cdsWatchers []AgentConfigChangeWatcher)
SendTracing(spans []ReportedSpan)
SendMetrics(metrics []ReportedMeter)
SendLog(log *logv3.LogData)
ConnectionStatus() ConnectionStatus
+ AddProfileTaskManager(p ProfileTaskManager)
Close()
}
diff --git a/plugins/core/reporter/discard_reporter.go
b/plugins/core/reporter/discard_reporter.go
index e1b5f38..7c0578d 100644
--- a/plugins/core/reporter/discard_reporter.go
+++ b/plugins/core/reporter/discard_reporter.go
@@ -44,3 +44,6 @@ func (r *discardReporter) ConnectionStatus() ConnectionStatus
{
func (r *discardReporter) Close() {
// do nothing
}
+func (r *discardReporter) AddProfileTaskManager(p ProfileTaskManager) {
+ // do nothing
+}
diff --git a/plugins/core/reporter/grpc/grpc.go
b/plugins/core/reporter/grpc/grpc.go
index 9d2ba5d..7f21ad3 100644
--- a/plugins/core/reporter/grpc/grpc.go
+++ b/plugins/core/reporter/grpc/grpc.go
@@ -24,12 +24,13 @@ import (
"google.golang.org/grpc/metadata"
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/reporter"
+ common "github.com/apache/skywalking-go/protocols/collect/common/v3"
agentv3
"github.com/apache/skywalking-go/protocols/collect/language/agent/v3"
+ profilev3
"github.com/apache/skywalking-go/protocols/collect/language/profile/v3"
logv3 "github.com/apache/skywalking-go/protocols/collect/logging/v3"
managementv3
"github.com/apache/skywalking-go/protocols/collect/management/v3"
-
- "github.com/apache/skywalking-go/plugins/core/operator"
- "github.com/apache/skywalking-go/plugins/core/reporter"
)
const (
@@ -40,26 +41,28 @@ const (
func NewGRPCReporter(logger operator.LogOperator,
serverAddr string,
checkInterval time.Duration,
+ profileFetchInterval time.Duration,
connManager *reporter.ConnectionManager,
cdsManager *reporter.CDSManager,
pprofTaskManager *reporter.PprofTaskManager,
opts ...ReporterOption,
) (reporter.Reporter, error) {
r := &gRPCReporter{
- logger: logger,
- serverAddr: serverAddr,
- tracingSendCh: make(chan *agentv3.SegmentObject,
maxSendQueueSize),
- metricsSendCh: make(chan []*agentv3.MeterData,
maxSendQueueSize),
- logSendCh: make(chan *logv3.LogData, maxSendQueueSize),
- checkInterval: checkInterval,
- connManager: connManager,
- cdsManager: cdsManager,
- pprofTaskManager: pprofTaskManager,
+ logger: logger,
+ serverAddr: serverAddr,
+ tracingSendCh: make(chan *agentv3.SegmentObject,
maxSendQueueSize),
+ metricsSendCh: make(chan []*agentv3.MeterData,
maxSendQueueSize),
+ logSendCh: make(chan *logv3.LogData,
maxSendQueueSize),
+ checkInterval: checkInterval,
+ profileFetchInterval: profileFetchInterval,
+ connManager: connManager,
+ cdsManager: cdsManager,
+ pprofTaskManager: pprofTaskManager,
}
for _, o := range opts {
o(r)
}
-
+ r.lastProfileCommandTime = -1
conn, err := connManager.GetConnection(serverAddr)
if err != nil {
return nil, err
@@ -68,22 +71,27 @@ func NewGRPCReporter(logger operator.LogOperator,
r.metricsClient = agentv3.NewMeterReportServiceClient(conn)
r.logClient = logv3.NewLogReportServiceClient(conn)
r.managementClient = managementv3.NewManagementServiceClient(conn)
+ r.profileTaskClient = profilev3.NewProfileTaskClient(conn)
return r, nil
}
type gRPCReporter struct {
- entity *reporter.Entity
- serverAddr string
- logger operator.LogOperator
- tracingSendCh chan *agentv3.SegmentObject
- metricsSendCh chan []*agentv3.MeterData
- logSendCh chan *logv3.LogData
- traceClient agentv3.TraceSegmentReportServiceClient
- metricsClient agentv3.MeterReportServiceClient
- logClient logv3.LogReportServiceClient
- managementClient managementv3.ManagementServiceClient
- checkInterval time.Duration
-
+ entity *reporter.Entity
+ serverAddr string
+ logger operator.LogOperator
+ tracingSendCh chan *agentv3.SegmentObject
+ metricsSendCh chan []*agentv3.MeterData
+ logSendCh chan *logv3.LogData
+ traceClient agentv3.TraceSegmentReportServiceClient
+ metricsClient agentv3.MeterReportServiceClient
+ logClient logv3.LogReportServiceClient
+ managementClient managementv3.ManagementServiceClient
+ profileTaskClient profilev3.ProfileTaskClient
+ profileTaskManager reporter.ProfileTaskManager
+ checkInterval time.Duration
+ profileFetchInterval time.Duration
+ // lastProfileCommandTime is the last timestamp we used to fetch
profile commands.
+ lastProfileCommandTime int64
// bootFlag is set if Boot be executed
bootFlag bool
transform *reporter.Transform
@@ -97,6 +105,7 @@ func (r *gRPCReporter) Boot(entity *reporter.Entity,
cdsWatchers []reporter.Agen
r.transform = reporter.NewTransform(entity)
r.initSendPipeline()
r.check()
+ r.fetchProfileTasks()
r.cdsManager.InitCDS(entity, cdsWatchers)
r.pprofTaskManager.InitPprofTask(entity)
r.bootFlag = true
@@ -283,6 +292,62 @@ func (r *gRPCReporter) initSendPipeline() {
break
}
}()
+ go func() {
+ defer func() {
+ if err := recover(); err != nil {
+ r.logger.Errorf("gRPCReporter
reportProfileResult panic err %v", err)
+ }
+ }()
+
+ StreamLoop:
+ for {
+ switch r.connManager.GetConnectionStatus(r.serverAddr) {
+ case reporter.ConnectionStatusShutdown:
+ break
+ case reporter.ConnectionStatusDisconnect:
+ time.Sleep(5 * time.Second)
+ continue StreamLoop
+ }
+
+ stream, err :=
r.profileTaskClient.GoProfileReport(metadata.NewOutgoingContext(context.Background(),
r.connManager.GetMD()))
+ if err != nil {
+ r.logger.Errorf("open profile stream error %v",
err)
+ time.Sleep(5 * time.Second)
+ continue StreamLoop
+ }
+ re := r.profileTaskManager.GetProfileResults()
+
+ for task := range re {
+ profileData := &profilev3.GoProfileData{
+ TaskId: task.TaskID,
+ Payload: task.Payload,
+ IsLast: task.IsLast,
+ }
+ r.logger.Infof("Sending profile task:
TaskID='%s', PayloadSize=%d, IsLast=%v",
+ task.TaskID, len(task.Payload),
task.IsLast)
+ err = stream.Send(profileData)
+ if err != nil {
+ r.logger.Errorf("send profile data
error %v", err)
+ r.closeProfileStream(stream)
+ continue StreamLoop
+ }
+ if task.IsLast {
+ r.profileTaskManager.ProfileFinish()
+ var report =
profilev3.ProfileTaskFinishReport{
+ TaskId: task.TaskID,
+ Service:
r.entity.ServiceName,
+ ServiceInstance:
r.entity.ServiceInstanceName,
+ }
+ _, err =
r.profileTaskClient.ReportTaskFinish(metadata.NewOutgoingContext(context.Background(),
r.connManager.GetMD()), &report)
+ if err != nil {
+ r.logger.Errorf("report profile
task finish error %v", err)
+ }
+ }
+ }
+ r.closeProfileStream(stream)
+ break
+ }
+ }()
}
func (r *gRPCReporter) closeTracingStream(stream
agentv3.TraceSegmentReportService_CollectClient) {
@@ -305,7 +370,12 @@ func (r *gRPCReporter) closeLogStream(stream
logv3.LogReportService_CollectClien
r.logger.Errorf("send closing error %v", err)
}
}
-
+func (r *gRPCReporter) closeProfileStream(stream
profilev3.ProfileTask_GoProfileReportClient) {
+ _, err := stream.CloseAndRecv()
+ if err != nil && err != io.EOF {
+ r.logger.Errorf("send profile closing error %v", err)
+ }
+}
func (r *gRPCReporter) reportInstanceProperties() (err error) {
_, err = r.managementClient.ReportInstanceProperties(
metadata.NewOutgoingContext(context.Background(),
r.connManager.GetMD()),
@@ -361,3 +431,52 @@ func (r *gRPCReporter) check() {
}
}()
}
+
+func (r *gRPCReporter) fetchProfileTasks() {
+ if r.profileFetchInterval < 0 {
+ r.logger.Errorf("profile init error:profileFetchInterval is
%v", r.profileFetchInterval)
+ return
+ }
+ go func() {
+ for {
+ // Construct the request
+ req := &profilev3.ProfileTaskCommandQuery{
+ Service: r.entity.ServiceName,
+ ServiceInstance: r.entity.ServiceInstanceName,
+ LastCommandTime: r.lastProfileCommandTime,
+ }
+
+ // Pull tasks
+ resp, err :=
r.profileTaskClient.GetProfileTaskCommands(context.Background(), req)
+ if err != nil {
+ r.logger.Errorf("fetch profile task error: %v",
err)
+ time.Sleep(r.profileFetchInterval)
+ continue
+ }
+
+ // Handle all returned commands
+ for _, cmd := range resp.Commands {
+ nt := r.handleProfileTask(cmd,
r.lastProfileCommandTime)
+ if nt > r.lastProfileCommandTime {
+ r.lastProfileCommandTime = nt
+ }
+ }
+
+ // Remove completed tasks
+ r.profileTaskManager.RemoveProfileTask()
+ time.Sleep(r.profileFetchInterval)
+ }
+ }()
+}
+
+func (r *gRPCReporter) AddProfileTaskManager(p reporter.ProfileTaskManager) {
+ r.profileTaskManager = p
+}
+
+func (r *gRPCReporter) handleProfileTask(cmd *common.Command, t int64) int64 {
+ if cmd.Command != "ProfileTaskQuery" {
+ return t
+ }
+ nt := r.profileTaskManager.AddProfileTask(cmd.Args, t)
+ return nt
+}
diff --git a/plugins/core/reporter/kafka/kafka.go
b/plugins/core/reporter/kafka/kafka.go
index c0c1430..012f9f2 100644
--- a/plugins/core/reporter/kafka/kafka.go
+++ b/plugins/core/reporter/kafka/kafka.go
@@ -351,3 +351,5 @@ func (r *kafkaReporter) Close() {
}
}
}
+
+func (r *kafkaReporter) AddProfileTaskManager(p reporter.ProfileTaskManager) {}
diff --git a/plugins/core/reporter/profile.go b/plugins/core/reporter/profile.go
new file mode 100644
index 0000000..63096ef
--- /dev/null
+++ b/plugins/core/reporter/profile.go
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 reporter
+
+import (
+ "time"
+
+ common "github.com/apache/skywalking-go/protocols/collect/common/v3"
+)
+
+type ProfileTaskManager interface {
+ // AddProfileTask add new profile task
+ AddProfileTask(args []*common.KeyStringValuePair, t int64) int64
+ GetProfileResults() chan ProfileResult
+ ProfileFinish()
+ RemoveProfileTask()
+}
+
+type TraceProfileTask struct {
+ SerialNumber string // uuid
+ TaskID string
+ EndpointName string // endpoint
+ Duration int // monitoring duration (min)
+ MinDurationThreshold int64 // starting monitoring time (ms)
+ DumpPeriod int // monitoring interval (ms)
+ MaxSamplingCount int // maximum number of samples
+ StartTime time.Time
+ CreateTime time.Time
+ Status ProfileTaskStatus // task execution status
+ EndTime time.Time // task deadline
+}
+
+type ProfileResult struct {
+ Payload []byte
+ TraceSegmentID string
+ TaskID string
+ IsLast bool
+}
diff --git a/plugins/core/span.go b/plugins/core/span.go
index 89e2748..219a7bc 100644
--- a/plugins/core/span.go
+++ b/plugins/core/span.go
@@ -50,4 +50,5 @@ type TracingSpan interface {
IsExit() bool
IsValid() bool
ParentSpan() TracingSpan
+ IsProfileTarget() bool
}
diff --git a/plugins/core/span_default.go b/plugins/core/span_default.go
index d55593b..4c6a5aa 100644
--- a/plugins/core/span_default.go
+++ b/plugins/core/span_default.go
@@ -158,6 +158,7 @@ func (ds *DefaultSpan) ErrorOccured() {
func (ds *DefaultSpan) End(changeParent bool) {
ds.EndTime = time.Now()
+
GetSo11y(ds.tracer).MeasureTracingContextCompletion(false)
if changeParent {
if ctx := getTracingContext(); ctx != nil {
@@ -211,3 +212,11 @@ func (ds *DefaultSpan) GetEndPointName() string {
func (ds *DefaultSpan) GetParentSpan() interface{} {
return ds.Parent
}
+
+func (ds *DefaultSpan) IsProfileTarget() bool {
+ endPoint := ds.GetEndPointName()
+ if ds.tracer.ProfileManager.IfProfiling() {
+ return ds.tracer.ProfileManager.CheckIfProfileTarget(endPoint)
+ }
+ return false
+}
diff --git a/plugins/core/span_noop.go b/plugins/core/span_noop.go
index 5fb09ab..dc6e476 100644
--- a/plugins/core/span_noop.go
+++ b/plugins/core/span_noop.go
@@ -35,6 +35,10 @@ func newSnapshotNoopSpan() *NoopSpan {
}
}
+func (*NoopSpan) IsProfileTarget() bool {
+ return false
+}
+
func newNoopSpan(tracer *Tracer) *NoopSpan {
return &NoopSpan{
stackCount: 1,
diff --git a/plugins/core/span_tracing.go b/plugins/core/span_tracing.go
index fc17d10..8aaeab6 100644
--- a/plugins/core/span_tracing.go
+++ b/plugins/core/span_tracing.go
@@ -231,6 +231,10 @@ func (s *SegmentSpanImpl) createSegmentContext(ctx
*TracingContext, parent Segme
return
}
+func (s *SegmentSpanImpl) IsProfileTarget() bool {
+ return s.DefaultSpan.IsProfileTarget()
+}
+
type RootSegmentSpan struct {
*SegmentSpanImpl
notify <-chan reporter.ReportedSpan
@@ -275,6 +279,10 @@ func (rs *RootSegmentSpan) createRootSegmentContext(ctx
*TracingContext, _ Segme
return
}
+func (rs *RootSegmentSpan) IsProfileTarget() bool {
+ return rs.DefaultSpan.IsProfileTarget()
+}
+
type SnapshotSpan struct {
DefaultSpan
SegmentContext
@@ -413,3 +421,7 @@ func newSnapshotSpan(current TracingSpan) TracingSpan {
return s
}
+
+func (s *SnapshotSpan) IsProfileTarget() bool {
+ return s.DefaultSpan.IsProfileTarget()
+}
diff --git a/plugins/core/test_base.go b/plugins/core/test_base.go
index 956955c..8cd197c 100644
--- a/plugins/core/test_base.go
+++ b/plugins/core/test_base.go
@@ -47,6 +47,9 @@ func ResetTracingContext() {
SetGLS(nil)
Tracing = &Tracer{initFlag: 1, Sampler: NewConstSampler(true),
Reporter: &StoreReporter{},
ServiceEntity: NewEntity("test", "test-instance"), meterMap:
&sync.Map{}}
+ // Initialize ProfileManager to avoid nil pointer dereference
+ Tracing.ProfileManager = NewProfileManager(nil)
+ Tracing.Reporter.AddProfileTaskManager(Tracing.ProfileManager)
SetAsNewGoroutine()
ReportConnectionStatus = reporter.ConnectionStatusConnected
}
@@ -96,3 +99,5 @@ func (r *StoreReporter) ConnectionStatus()
reporter.ConnectionStatus {
func (r *StoreReporter) Close() {
}
+
+func (r *StoreReporter) AddProfileTaskManager(p reporter.ProfileTaskManager) {}
diff --git a/plugins/core/trace_profiling_event_manager.go
b/plugins/core/trace_profiling_event_manager.go
new file mode 100644
index 0000000..16e647c
--- /dev/null
+++ b/plugins/core/trace_profiling_event_manager.go
@@ -0,0 +1,165 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 core
+
+import (
+ "strconv"
+ "sync"
+
+ "github.com/pkg/errors"
+)
+
+type TraceProfilingBaseEvent string
+
+type TraceProfilingComplexEvent string
+
+type TraceProfilingLogicOp int
+
+const (
+ OpAnd TraceProfilingLogicOp = iota // AND: all conditions must be
true
+ OpOr // OR: at least one condition
must be true
+ OpNothing // Do nothing, used for initial
rules
+)
+
+type TraceProfilingRule struct {
+ Event TraceProfilingBaseEvent
+ Op TraceProfilingLogicOp
+ IsNot bool
+}
+
+// Expression node (used to build logical expression trees)
+type TraceProfilingExprNode struct {
+ Rules []TraceProfilingRule
+ Event TraceProfilingComplexEvent
+}
+
+// TraceProfilingEventManager manages event states and logical rules
+// You can register basic events and states in the manager,
+// and then define complex events by combining these basic events using
logical operators (AND, OR, NOT).
+// This makes it easier to manage whether complex events can be executed.
+type TraceProfilingEventManager struct {
+ mu sync.RWMutex
+ BaseEventStatus map[TraceProfilingBaseEvent]bool
// current status of base events (true=enabled, false=disabled)
+ ComplexEvents map[TraceProfilingComplexEvent]*TraceProfilingExprNode
// logical expressions for complex events
+}
+
+// Create a new TraceProfilingEventManager
+func NewEventManager() *TraceProfilingEventManager {
+ return &TraceProfilingEventManager{
+ BaseEventStatus: make(map[TraceProfilingBaseEvent]bool),
+ ComplexEvents:
make(map[TraceProfilingComplexEvent]*TraceProfilingExprNode),
+ }
+}
+
+// Register a base event with initial status
+func (m *TraceProfilingEventManager) RegisterBaseEvent(event
TraceProfilingBaseEvent, initialStatus bool) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.BaseEventStatus[event] = initialStatus
+}
+
+// Register a complex event with logical expression rules
+func (m *TraceProfilingEventManager) RegisterComplexEvent(targetEvent
TraceProfilingComplexEvent, expr *TraceProfilingExprNode) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ m.ComplexEvents[targetEvent] = expr
+}
+
+// Update the status of a base event
+func (m *TraceProfilingEventManager) UpdateBaseEventStatus(event
TraceProfilingBaseEvent, status bool) error {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ if _, ok := m.BaseEventStatus[event]; !ok {
+ return errors.New("event not registered")
+ }
+ m.BaseEventStatus[event] = status
+ return nil
+}
+
+// Get the status of a base event
+func (m *TraceProfilingEventManager) GetBaseEventStatus(event
TraceProfilingBaseEvent) (bool, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ status, ok := m.BaseEventStatus[event]
+ if !ok {
+ return false, errors.New("event not registered")
+ }
+ return status, nil
+}
+
+// Execute a complex event by evaluating its logical expression
+func (m *TraceProfilingEventManager) ExecuteComplexEvent(event
TraceProfilingComplexEvent) (bool, error) {
+ m.mu.RLock()
+ defer m.mu.RUnlock()
+ expr, ok := m.ComplexEvents[event]
+ if !ok {
+ return false, errors.New("event not registered")
+ }
+ return m.evalExpr(expr)
+}
+
+// Recursively evaluate the logical expression
+func (m *TraceProfilingEventManager) evalExpr(node *TraceProfilingExprNode)
(bool, error) {
+ if len(node.Rules) == 0 {
+ return false, errors.New("complex event has no rules")
+ }
+
+ // 1. Evaluate the first rule directly (with optional NOT operation)
+ firstRule := node.Rules[0]
+ currentResult, err := m.getRuleValue(firstRule)
+ if err != nil {
+ return false, err
+ }
+
+ // 2. From the second rule onward, combine results using logical
operators
+ for i := 1; i < len(node.Rules); i++ {
+ rule := node.Rules[i]
+ // Get the value of the current rule (with optional NOT)
+ ruleValue, err := m.getRuleValue(rule)
+ if err != nil {
+ return false, err
+ }
+ switch rule.Op {
+ case OpAnd:
+ currentResult = currentResult && ruleValue
+ case OpOr:
+ currentResult = currentResult || ruleValue
+ default:
+ return false, errors.New("invalid logic op: " +
strconv.Itoa(int(rule.Op)))
+ }
+ }
+
+ return currentResult, nil
+}
+
+// Get the value of a base event for a rule (with optional NOT)
+func (m *TraceProfilingEventManager) getRuleValue(rule TraceProfilingRule)
(bool, error) {
+ baseStatus, ok := m.BaseEventStatus[rule.Event]
+ if !ok {
+ return false, errors.New("base event not registered: " +
string(rule.Event))
+ }
+
+ // Apply NOT operator if specified
+ if rule.IsNot {
+ return !baseStatus, nil
+ }
+
+ // Otherwise return the base event status directly
+ return baseStatus, nil
+}
diff --git a/plugins/core/tracer.go b/plugins/core/tracer.go
index 3090502..5323ce6 100644
--- a/plugins/core/tracer.go
+++ b/plugins/core/tracer.go
@@ -38,8 +38,9 @@ type CorrelationConfig struct {
}
type Tracer struct {
- ServiceEntity *reporter.Entity
- Reporter reporter.Reporter
+ ServiceEntity *reporter.Entity
+ Reporter reporter.Reporter
+ ProfileManager *ProfileManager
// 0 not init 1 init
initFlag int32
Sampler Sampler
@@ -65,6 +66,8 @@ func (t *Tracer) Init(entity *reporter.Entity, rep
reporter.Reporter, samp Sampl
if logger != nil && !reflect.ValueOf(logger).IsZero() {
t.Log.ChangeLogger(logger)
}
+ t.ProfileManager = NewProfileManager(t.Log)
+ t.Reporter.AddProfileTaskManager(t.ProfileManager)
t.Reporter.Boot(entity, t.cdsWatchers)
t.initFlag = 1
t.initMetricsCollect(meterCollectSecond)
diff --git a/plugins/core/tracing.go b/plugins/core/tracing.go
index 65f8561..b11d4e0 100644
--- a/plugins/core/tracing.go
+++ b/plugins/core/tracing.go
@@ -38,6 +38,10 @@ func (t *Tracer) Logger() interface{} {
return t.Log
}
+func (t *Tracer) Profiler() interface{} {
+ return t.ProfileManager
+}
+
func (t *Tracer) DebugStack() []byte {
return debug.Stack()
}
@@ -64,6 +68,21 @@ func (t *Tracer) CreateEntrySpan(operationName string,
extractor interface{}, op
}
span, _, err := t.createSpan0(ctx, tracingSpan, opts, withRef(ref),
withSpanType(SpanTypeEntry), withOperationName(operationName))
+ if err == nil {
+ sid := span.GetSegmentID()
+ tid := span.GetTraceID()
+ // check if is profile target
+ if t.ProfileManager.CheckIfProfileTarget(operationName) {
+ // check if is profiling
+ if t.ProfileManager.IfProfiling() {
+ if segmentSpan, ok := span.(SegmentSpan); ok {
+ c := segmentSpan.GetSegmentContext()
+
t.ProfileManager.TryToAddSegmentLabelSet(sid)
+ t.ProfileManager.AddSpanID(tid, sid,
c.SpanID)
+ }
+ }
+ }
+ }
return span, err
}
@@ -77,6 +96,19 @@ func (t *Tracer) CreateLocalSpan(operationName string, opts
...interface{}) (s i
}()
span, _, err := t.createSpan0(ctx, tracingSpan, opts,
withSpanType(SpanTypeLocal), withOperationName(operationName))
+ if err == nil {
+ sid := span.GetSegmentID()
+ tid := span.GetTraceID()
+ endpoint := span.GetOperationName()
+ if t.ProfileManager.CheckIfProfileTarget(endpoint) {
+ if segmentSpan, ok := span.(SegmentSpan); ok {
+ c := segmentSpan.GetSegmentContext()
+ if t.ProfileManager.IfProfiling() {
+ t.ProfileManager.AddSpanID(tid, sid,
c.SpanID)
+ }
+ }
+ }
+ }
return span, err
}
diff --git a/plugins/core/tracing/api.go b/plugins/core/tracing/api.go
index 83e2a06..530aef1 100644
--- a/plugins/core/tracing/api.go
+++ b/plugins/core/tracing/api.go
@@ -240,3 +240,4 @@ func (n *NoopSpan) PrepareAsync() {
}
func (n *NoopSpan) AsyncFinish() {
}
+func (n *NoopSpan) IsProfileTarget() bool { return false }
diff --git a/plugins/core/tracing/bridge.go b/plugins/core/tracing/bridge.go
index 8b40b73..2d7216e 100644
--- a/plugins/core/tracing/bridge.go
+++ b/plugins/core/tracing/bridge.go
@@ -40,6 +40,7 @@ type AdaptSpan interface {
Error(...string)
ErrorOccured()
End()
+ IsProfileTarget() bool
}
type SpanWrapper struct {
@@ -105,3 +106,7 @@ func (s *SpanWrapper) PrepareAsync() {
func (s *SpanWrapper) AsyncFinish() {
s.Span.AsyncFinish()
}
+
+func (s *SpanWrapper) IsProfileTarget() bool {
+ return s.Span.IsProfileTarget()
+}
diff --git a/plugins/core/tracing/span.go b/plugins/core/tracing/span.go
index 641dcd7..e762f65 100644
--- a/plugins/core/tracing/span.go
+++ b/plugins/core/tracing/span.go
@@ -141,4 +141,6 @@ type Span interface {
ErrorOccured()
// End end the Span
End()
+ // check if is trace profile target
+ IsProfileTarget() bool
}
diff --git a/plugins/echov4/intercepter.go b/plugins/echov4/intercepter.go
index 6741457..c4e1005 100644
--- a/plugins/echov4/intercepter.go
+++ b/plugins/echov4/intercepter.go
@@ -60,7 +60,6 @@ func middleware() echo.MiddlewareFunc {
if err != nil {
return err
}
-
// serve the request to the next middleware
if err = next(c); err != nil {
span.Error(err.Error())
diff --git a/plugins/http/server_intercepter.go
b/plugins/http/server_intercepter.go
index a20dfac..2b52ecc 100644
--- a/plugins/http/server_intercepter.go
+++ b/plugins/http/server_intercepter.go
@@ -41,7 +41,6 @@ func (h *ServerInterceptor) BeforeInvoke(invocation
operator.Invocation) error {
if err != nil {
return err
}
-
if config.ServerCollectParameters && request.URL != nil {
s.Tag(tracing.TagHTTPParams, request.URL.RawQuery)
}
diff --git a/plugins/pprof/go.mod b/plugins/pprof/go.mod
new file mode 100644
index 0000000..d3ffce1
--- /dev/null
+++ b/plugins/pprof/go.mod
@@ -0,0 +1,3 @@
+module github.com/apache/skywalking-go/plugins/pprof
+
+go 1.19
diff --git a/plugins/pprof/instrument.go b/plugins/pprof/instrument.go
new file mode 100644
index 0000000..156ac5e
--- /dev/null
+++ b/plugins/pprof/instrument.go
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 pprof
+
+import (
+ "embed"
+
+ "github.com/apache/skywalking-go/plugins/core/instrument"
+)
+
+//go:embed *
+var fs embed.FS
+
+//skywalking:nocopy
+type Instrument struct{}
+
+func NewInstrument() *Instrument {
+ return &Instrument{}
+}
+
+func (i *Instrument) Name() string {
+ return "profile"
+}
+
+func (i *Instrument) BasePackage() string {
+ return "runtime/pprof"
+}
+
+func (i *Instrument) VersionChecker(version string) bool {
+ return true
+}
+
+func (i *Instrument) Points() []*instrument.Point {
+ return []*instrument.Point{
+ {
+ PackagePath: "",
+ At: instrument.NewStaticMethodEnhance(
+ "SetGoroutineLabels",
+ instrument.WithArgsCount(1),
+ instrument.WithArgType(0, "context.Context"),
+ ),
+ Interceptor: "SetLabelsInterceptor",
+ },
+ }
+}
+
+func (i *Instrument) FS() *embed.FS {
+ return &fs
+}
diff --git a/plugins/pprof/intercepter.go b/plugins/pprof/intercepter.go
new file mode 100644
index 0000000..f4a0a20
--- /dev/null
+++ b/plugins/pprof/intercepter.go
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 pprof
+
+import (
+ "context"
+ "errors"
+ "runtime/pprof"
+
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/profile"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type SetLabelsInterceptor struct{}
+
+func (h *SetLabelsInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ c := invocation.Args()[0].(context.Context)
+ if tracing.ActiveSpan() == nil {
+ return nil
+ }
+ if !tracing.ActiveSpan().IsProfileTarget() {
+ return nil
+ }
+ now := profile.CatchNowProfileLabel()
+ l, ok := now.(pprof.LabelSet)
+ if !ok {
+ return errors.New("profile label transform error")
+ }
+ c = pprof.WithLabels(c, l)
+ invocation.ChangeArg(0, c)
+ return nil
+}
+
+func (h *SetLabelsInterceptor) AfterInvoke(invocation operator.Invocation,
result ...interface{}) error {
+ return nil
+}
diff --git a/test/benchmark-codebase/consumer/main.go
b/test/benchmark-codebase/consumer/main.go
index 9f92bf4..987041f 100644
--- a/test/benchmark-codebase/consumer/main.go
+++ b/test/benchmark-codebase/consumer/main.go
@@ -110,7 +110,7 @@ func startPprof() {
}
go func() {
if err := svr.ListenAndServe(); err != nil {
- log.Printf("starting pprof server failure: %v", err)
+ log.Printf("starting profile server failure: %v", err)
}
}()
}
diff --git a/test/e2e/case/kafka/docker-compose.yml
b/test/e2e/case/kafka/docker-compose.yml
index 1679bf4..c9e4c8d 100644
--- a/test/e2e/case/kafka/docker-compose.yml
+++ b/test/e2e/case/kafka/docker-compose.yml
@@ -32,7 +32,7 @@ services:
retries: 120
broker-a:
- image: bitnami/kafka:2.4.1
+ image: bitnamilegacy/kafka:2.4.1
hostname: broker-a
expose:
- 9092
@@ -53,7 +53,7 @@ services:
retries: 120
broker-b:
- image: bitnami/kafka:2.4.1
+ image: bitnamilegacy/kafka:2.4.1
hostname: broker-b
expose:
- 9092
diff --git a/test/plugins/runner-helper/templates/docker-compose.tpl
b/test/plugins/runner-helper/templates/docker-compose.tpl
index 43ccc9b..a7410af 100644
--- a/test/plugins/runner-helper/templates/docker-compose.tpl
+++ b/test/plugins/runner-helper/templates/docker-compose.tpl
@@ -21,7 +21,7 @@ networks:
services:
oap:
- image:
ghcr.io/apache/skywalking-agent-test-tool/mock-collector:fa81b1b6d9caef484a65b5019efa28cac4e3d21d
+ image:
ghcr.io/apache/skywalking-agent-test-tool/mock-collector:b22b7d8ba62dabdd8db1ecc52da6178b063edff7
expose:
- 19876
- 12800
diff --git a/test/plugins/runner-helper/templates/windows-docker-compose.tpl
b/test/plugins/runner-helper/templates/windows-docker-compose.tpl
index befd6f6..2b42f50 100644
--- a/test/plugins/runner-helper/templates/windows-docker-compose.tpl
+++ b/test/plugins/runner-helper/templates/windows-docker-compose.tpl
@@ -17,7 +17,7 @@ version: '2.1'
services:
oap:
- image:
ghcr.io/apache/skywalking-agent-test-tool/mock-collector:fa81b1b6d9caef484a65b5019efa28cac4e3d21d
+ image:
ghcr.io/apache/skywalking-agent-test-tool/mock-collector:b22b7d8ba62dabdd8db1ecc52da6178b063edff7
network_mode: host
expose:
- 19876
diff --git a/test/plugins/scenarios/logrus/config/excepted.yml
b/test/plugins/scenarios/logrus/config/excepted.yml
index 88bfca1..59c9d4d 100644
--- a/test/plugins/scenarios/logrus/config/excepted.yml
+++ b/test/plugins/scenarios/logrus/config/excepted.yml
@@ -18,13 +18,14 @@ segmentItems: []
meterItems: []
logItems:
- serviceName: logrus
- logSize: ge 4
+ logSize: ge 5
logs:
- timestamp: nq 0
endpoint: ''
body:
type: TEXT
- content: { text: not null }
+ content: { text: 'fetch dynamic configuration error rpc error: code
= Unimplemented
+ desc = Method not found:
skywalking.v3.ConfigurationDiscoveryService/fetchConfigurations' }
traceContext: { traceId: N/A, traceSegmentId: N/A, spanId: -1 }
tags:
data:
@@ -34,7 +35,19 @@ logItems:
endpoint: ''
body:
type: TEXT
- content: { text: not null }
+ content: { text: 'fetch pprof task commands error rpc error: code =
Unimplemented
+ desc = Method not found:
skywalking.v10.PprofTask/getPprofTaskCommands' }
+ traceContext: { traceId: N/A, traceSegmentId: N/A, spanId: -1 }
+ tags:
+ data:
+ - { key: LEVEL, value: error }
+ layer: GENERAL
+ - timestamp: nq 0
+ endpoint: ''
+ body:
+ type: TEXT
+ content: { text: 'fetch profile task error: rpc error: code =
Unimplemented
+ desc = Method not found:
skywalking.v3.ProfileTask/getProfileTaskCommands' }
traceContext: { traceId: N/A, traceSegmentId: N/A, spanId: -1 }
tags:
data:
diff --git a/test/plugins/scenarios/segmentio-kafka/plugin.yml
b/test/plugins/scenarios/pprof/bin/startup.sh
similarity index 54%
copy from test/plugins/scenarios/segmentio-kafka/plugin.yml
copy to test/plugins/scenarios/pprof/bin/startup.sh
index 9b7f3b9..45c692f 100644
--- a/test/plugins/scenarios/segmentio-kafka/plugin.yml
+++ b/test/plugins/scenarios/pprof/bin/startup.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -14,27 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-entry-service: http://${HTTP_HOST}:${HTTP_PORT}/execute
-health-checker: http://${HTTP_HOST}:${HTTP_PORT}/health
-start-script: ./bin/startup.sh
-framework: github.com/segmentio/kafka-go
-export-port: 8080
-support-version:
- - go: 1.19
- framework:
- - v0.4.47
-dependencies:
- zookeeper-server:
- image: zookeeper:3.9.2
- hostname: zookeeper-server
- kafka-server:
- image: bitnami/kafka:3.7.0
- hostname: kafka-server
- ports:
- - 9092
- environment:
- KAFKA_ZOOKEEPER_CONNECT: "zookeeper-server:2181"
- KAFKA_BROKER_ID: 1
- KAFKA_LISTENERS: "PLAINTEXT://kafka-server:9092"
- depends_on:
- - zookeeper-server
\ No newline at end of file
+home="$(cd "$(dirname $0)"; pwd)"
+go build ${GO_BUILD_OPTS} -o pprof
+
+./pprof
\ No newline at end of file
diff --git a/test/plugins/scenarios/pprof/config/excepted.yml
b/test/plugins/scenarios/pprof/config/excepted.yml
new file mode 100644
index 0000000..dc1b742
--- /dev/null
+++ b/test/plugins/scenarios/pprof/config/excepted.yml
@@ -0,0 +1,114 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+segmentItems:
+ - serviceName: pprof
+ segmentSize: ge 3
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: GET:/provider
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5004
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'localhost:8080/provider'}
+ - {key: http.params, value: 'test=1'}
+ - {key: status_code, value: '200'}
+ refs:
+ - {parentEndpoint: 'GET:/consumer', networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstance: not null,
+ parentService: pprof, traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/provider
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5004
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'localhost:8080/provider'}
+ - {key: http.params, value: 'test=2'}
+ - {key: status_code, value: '200'}
+ refs:
+ - {parentEndpoint: 'GET:/consumer', networkAddress:
'localhost:8080', refType: CrossProcess,
+ parentSpanId: 2, parentTraceSegmentId: not null,
parentServiceInstance: not null,
+ parentService: pprof, traceId: not null}
+ - segmentId: not null
+ spans:
+ - operationName: GET:/provider
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 5005
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'localhost:8080/provider'}
+ - {key: status_code, value: '200'}
+ - operationName: GET:/provider
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 5005
+ isError: false
+ spanType: Exit
+ peer: localhost:8080
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'localhost:8080/provider'}
+ - {key: status_code, value: '200'}
+ - operationName: GET:/consumer
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 5004
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: http.method, value: GET}
+ - {key: url, value: 'service:8080/consumer'}
+ - {key: http.params, value: ''}
+ - {key: status_code, value: '200'}
+meterItems: []
+logItems: []
\ No newline at end of file
diff --git a/test/plugins/scenarios/pprof/go.mod
b/test/plugins/scenarios/pprof/go.mod
new file mode 100644
index 0000000..303901c
--- /dev/null
+++ b/test/plugins/scenarios/pprof/go.mod
@@ -0,0 +1,3 @@
+module test/plugins/scenarios/pprof
+
+go 1.19
diff --git a/test/plugins/scenarios/pprof/main.go
b/test/plugins/scenarios/pprof/main.go
new file mode 100644
index 0000000..1891640
--- /dev/null
+++ b/test/plugins/scenarios/pprof/main.go
@@ -0,0 +1,96 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you 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 main
+
+import (
+ "context"
+ "io"
+ "log"
+ "net/http"
+ "runtime/pprof"
+ "time"
+
+ _ "github.com/apache/skywalking-go"
+)
+
+func providerHandler(w http.ResponseWriter, r *http.Request) {
+ l := pprof.Labels("test-label", "test", "operation", "provider")
+ c := context.Background()
+ c = pprof.WithLabels(c, l)
+
+ pprof.SetGoroutineLabels(c)
+
+ doWork()
+ _, _ = w.Write([]byte("success"))
+}
+
+func consumerHandler(w http.ResponseWriter, r *http.Request) {
+ l := pprof.Labels("test-label", "consumer", "operation", "consumer")
+ c := context.Background()
+ c = pprof.WithLabels(c, l)
+ pprof.SetGoroutineLabels(c)
+
+ resp, err := http.Get("http://localhost:8080/provider?test=1")
+ if err != nil {
+ log.Printf("request provider error: %v", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ defer resp.Body.Close()
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ log.Print(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ resp2, err := http.Get("http://localhost:8080/provider?test=2")
+ if err != nil {
+ log.Printf("request provider error: %v", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ defer resp2.Body.Close()
+ body2, err := io.ReadAll(resp2.Body)
+ if err != nil {
+ log.Print(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ _, _ = w.Write(append(body, body2...))
+}
+
+func doWork() {
+ start := time.Now()
+ for time.Since(start) < 1*time.Second {
+ for i := 0; i < 1e6; i++ {
+ _ = i * i
+ }
+ }
+}
+
+func main() {
+ http.HandleFunc("/provider", providerHandler)
+ http.HandleFunc("/consumer", consumerHandler)
+
+ http.HandleFunc("/health", func(writer http.ResponseWriter, request
*http.Request) {
+ writer.WriteHeader(http.StatusOK)
+ })
+ _ = http.ListenAndServe("0.0.0.0:8080", nil)
+}
diff --git a/test/plugins/scenarios/segmentio-kafka/plugin.yml
b/test/plugins/scenarios/pprof/plugin.yml
similarity index 64%
copy from test/plugins/scenarios/segmentio-kafka/plugin.yml
copy to test/plugins/scenarios/pprof/plugin.yml
index 9b7f3b9..ada27b8 100644
--- a/test/plugins/scenarios/segmentio-kafka/plugin.yml
+++ b/test/plugins/scenarios/pprof/plugin.yml
@@ -1,40 +1,28 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you 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.
-
-entry-service: http://${HTTP_HOST}:${HTTP_PORT}/execute
-health-checker: http://${HTTP_HOST}:${HTTP_PORT}/health
-start-script: ./bin/startup.sh
-framework: github.com/segmentio/kafka-go
-export-port: 8080
-support-version:
- - go: 1.19
- framework:
- - v0.4.47
-dependencies:
- zookeeper-server:
- image: zookeeper:3.9.2
- hostname: zookeeper-server
- kafka-server:
- image: bitnami/kafka:3.7.0
- hostname: kafka-server
- ports:
- - 9092
- environment:
- KAFKA_ZOOKEEPER_CONNECT: "zookeeper-server:2181"
- KAFKA_BROKER_ID: 1
- KAFKA_LISTENERS: "PLAINTEXT://kafka-server:9092"
- depends_on:
- - zookeeper-server
\ No newline at end of file
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+entry-service: http://${HTTP_HOST}:${HTTP_PORT}/consumer
+health-checker: http://${HTTP_HOST}:${HTTP_PORT}/health
+start-script: ./bin/startup.sh
+framework: go
+export-port: 8080
+support-version:
+ - go: 1.19
+ - go: 1.20
+ - go: 1.21
+ - go: 1.22
+ - go: 1.23
+toolkit: true
\ No newline at end of file
diff --git a/test/plugins/scenarios/segmentio-kafka/plugin.yml
b/test/plugins/scenarios/segmentio-kafka/plugin.yml
index 9b7f3b9..648e02c 100644
--- a/test/plugins/scenarios/segmentio-kafka/plugin.yml
+++ b/test/plugins/scenarios/segmentio-kafka/plugin.yml
@@ -28,7 +28,7 @@ dependencies:
image: zookeeper:3.9.2
hostname: zookeeper-server
kafka-server:
- image: bitnami/kafka:3.7.0
+ image: bitnamilegacy/kafka:3.7.0
hostname: kafka-server
ports:
- 9092
diff --git a/test/plugins/scenarios/zap/config/excepted.yml
b/test/plugins/scenarios/zap/config/excepted.yml
index dd1b2d8..b505d05 100644
--- a/test/plugins/scenarios/zap/config/excepted.yml
+++ b/test/plugins/scenarios/zap/config/excepted.yml
@@ -18,13 +18,14 @@ segmentItems: []
meterItems: []
logItems:
- serviceName: zap
- logSize: ge 4
+ logSize: ge 5
logs:
- timestamp: nq 0
endpoint: ''
body:
type: TEXT
- content: { text: not null }
+ content: { text: 'fetch dynamic configuration error rpc error: code
= Unimplemented
+ desc = Method not found:
skywalking.v3.ConfigurationDiscoveryService/fetchConfigurations' }
traceContext: { traceId: N/A, traceSegmentId: N/A, spanId: -1 }
tags:
data:
@@ -34,7 +35,19 @@ logItems:
endpoint: ''
body:
type: TEXT
- content: { text: not null }
+ content: { text: 'fetch pprof task commands error rpc error: code =
Unimplemented
+ desc = Method not found:
skywalking.v10.PprofTask/getPprofTaskCommands' }
+ traceContext: { traceId: N/A, traceSegmentId: N/A, spanId: -1 }
+ tags:
+ data:
+ - { key: LEVEL, value: error }
+ layer: GENERAL
+ - timestamp: nq 0
+ endpoint: ''
+ body:
+ type: TEXT
+ content: { text: 'fetch profile task error: rpc error: code =
Unimplemented
+ desc = Method not found:
skywalking.v3.ProfileTask/getProfileTaskCommands' }
traceContext: { traceId: N/A, traceSegmentId: N/A, spanId: -1 }
tags:
data:
@@ -73,4 +86,4 @@ logItems:
value: info
- key: module
value: test-service-consumer
- layer: GENERAL
+ layer: GENERAL
\ No newline at end of file
diff --git a/tools/go-agent/config/agent.default.yaml
b/tools/go-agent/config/agent.default.yaml
index 02d351f..8281612 100644
--- a/tools/go-agent/config/agent.default.yaml
+++ b/tools/go-agent/config/agent.default.yaml
@@ -54,12 +54,13 @@ reporter:
authentication: ${SW_AGENT_REPORTER_GRPC_AUTHENTICATION:}
# The interval(s) of fetching dynamic configuration from backend.
cds_fetch_interval: ${SW_AGENT_REPORTER_GRPC_CDS_FETCH_INTERVAL:20}
+ # The interval(s) of fetching profile task from backend.
+ profile_fetch_interval: ${SW_AGENT_REPORTER_GRPC_PROFILE_FETCH_INTERVAL:20}
pprof:
# The interval(s) of fetching pprof task from backend.
pprof_fetch_interval:
${SW_AGENT_REPORTER_GRPC_PPROF_TASK_FETCH_INTERVAL:20}
# The pprof file path generated when executing the profile task.
pprof_file_path: ${SW_AGENT_REPORTER_GRPC_PROFILE_PPROF_FILE_PATH:}
-
tls:
# Whether to enable TLS with backend.
enable: ${SW_AGENT_REPORTER_GRPC_TLS_ENABLE:false}
diff --git a/tools/go-agent/config/loader.go b/tools/go-agent/config/loader.go
index 8d843df..a792cd6 100644
--- a/tools/go-agent/config/loader.go
+++ b/tools/go-agent/config/loader.go
@@ -83,12 +83,13 @@ type Meter struct {
}
type GRPCReporter struct {
- BackendService StringValue `yaml:"backend_service"`
- MaxSendQueue StringValue `yaml:"max_send_queue"`
- Authentication StringValue `yaml:"authentication"`
- CDSFetchInterval StringValue `yaml:"cds_fetch_interval"`
- TLS GRPCReporterTLS `yaml:"tls"`
- Pprof GRPCReporterPprof `yaml:"pprof"`
+ BackendService StringValue `yaml:"backend_service"`
+ MaxSendQueue StringValue `yaml:"max_send_queue"`
+ Authentication StringValue `yaml:"authentication"`
+ CDSFetchInterval StringValue `yaml:"cds_fetch_interval"`
+ ProfileFetchInterval StringValue `yaml:"profile_fetch_interval"`
+ TLS GRPCReporterTLS `yaml:"tls"`
+ Pprof GRPCReporterPprof `yaml:"pprof"`
}
type GRPCReporterPprof struct {
diff --git a/tools/go-agent/instrument/agentcore/instrument.go
b/tools/go-agent/instrument/agentcore/instrument.go
index 872b30c..d637bf7 100644
--- a/tools/go-agent/instrument/agentcore/instrument.go
+++ b/tools/go-agent/instrument/agentcore/instrument.go
@@ -44,7 +44,7 @@ var (
ReporterBasePackage = "agent/reporter"
CopiedBasePackage = `skywalking-go(@[\d\w\.\-]+)?\/agent\/core`
- CopiedSubPackages = []string{"", "tracing", "operator", "metrics"}
+ CopiedSubPackages = []string{"", "tracing", "operator", "metrics",
"profile"}
)
type Instrument struct {
diff --git a/tools/go-agent/instrument/plugins/register.go
b/tools/go-agent/instrument/plugins/register.go
index 27e15a9..680dc4e 100644
--- a/tools/go-agent/instrument/plugins/register.go
+++ b/tools/go-agent/instrument/plugins/register.go
@@ -40,6 +40,7 @@ import (
"github.com/apache/skywalking-go/plugins/microv4"
"github.com/apache/skywalking-go/plugins/mongo"
"github.com/apache/skywalking-go/plugins/mux"
+ "github.com/apache/skywalking-go/plugins/pprof"
"github.com/apache/skywalking-go/plugins/pulsar"
"github.com/apache/skywalking-go/plugins/rocketmq"
runtime_metrics "github.com/apache/skywalking-go/plugins/runtimemetrics"
@@ -68,6 +69,7 @@ func init() {
registerFramework(fiber.NewInstrument())
registerFramework(rocketmq.NewInstrument())
registerFramework(amqp.NewInstrument())
+ registerFramework(pprof.NewInstrument())
registerFramework(pulsar.NewInstrument())
registerFramework(segmentiokafka.NewInstrument())
registerFramework(goelasticsearchv8.NewInstrument())
diff --git a/tools/go-agent/instrument/plugins/rewrite/context.go
b/tools/go-agent/instrument/plugins/rewrite/context.go
index f741334..7f8fb3f 100644
--- a/tools/go-agent/instrument/plugins/rewrite/context.go
+++ b/tools/go-agent/instrument/plugins/rewrite/context.go
@@ -39,7 +39,7 @@ var GenerateCommonPrefix = "skywalking_"
var GenerateMethodPrefix = GenerateCommonPrefix + "enhance_"
var GenerateVarPrefix = GenerateCommonPrefix + "var_"
-var OperatorDirs = []string{"operator", "log", "tracing", "tools", "metrics"}
+var OperatorDirs = []string{"operator", "log", "tracing", "tools", "metrics",
"profile"}
var OperatePrefix = GenerateCommonPrefix + "operator"
var TypePrefix = OperatePrefix + "Type"
diff --git a/tools/go-agent/instrument/plugins/rewrite/func.go
b/tools/go-agent/instrument/plugins/rewrite/func.go
index eb1ddff..8cc93dd 100644
--- a/tools/go-agent/instrument/plugins/rewrite/func.go
+++ b/tools/go-agent/instrument/plugins/rewrite/func.go
@@ -77,8 +77,10 @@ func (c *Context) Func(funcDecl *dst.FuncDecl, cursor
*dstutil.Cursor) {
c.enhanceFuncParameter(funcDecl.Type.Results)
// enhance the method body
- for _, stmt := range funcDecl.Body.List {
- c.enhanceFuncStmt(stmt)
+ if funcDecl.Body != nil {
+ for _, stmt := range funcDecl.Body.List {
+ c.enhanceFuncStmt(stmt)
+ }
}
}
diff --git a/tools/go-agent/instrument/reporter/instrument.go
b/tools/go-agent/instrument/reporter/instrument.go
index 43bb06a..7b77e7c 100644
--- a/tools/go-agent/instrument/reporter/instrument.go
+++ b/tools/go-agent/instrument/reporter/instrument.go
@@ -203,7 +203,7 @@ func {{.InitFuncName}}(logger operator.LogOperator)
(Reporter, error) {
return NewDiscardReporter(), nil
}
checkIntervalVal := {{.Config.Reporter.CheckInterval.ToGoIntValue "the
reporter check interval must be number"}}
- checkInterval := time.Second * time.Duration(checkIntervalVal)
+ checkInterval := time.Second * time.Duration(checkIntervalVal)
`
const initManagerFunc = `
@@ -233,7 +233,7 @@ func initManager(logger operator.LogOperator, checkInterval
time.Duration) (*Con
}
cdsFetchIntervalVal :=
{{.Config.Reporter.GRPC.CDSFetchInterval.ToGoIntValue "the cds fetch interval
must be number"}}
- cdsFetchInterval := time.Second * time.Duration(cdsFetchIntervalVal)
+ cdsFetchInterval := time.Second * time.Duration(cdsFetchIntervalVal)
cdsManager, err := NewCDSManager(logger, backendServiceVal,
cdsFetchInterval, connManager)
if err != nil {
return nil, nil, nil, err
@@ -261,9 +261,11 @@ func initGRPCReporter(logger operator.LogOperator,
var opts []ReporterOption
maxSendQueueVal := {{.Config.Reporter.GRPC.MaxSendQueue.ToGoIntValue
"the GRPC reporter max queue size must be number"}}
opts = append(opts, WithMaxSendQueueSize(maxSendQueueVal))
-
+
backendServiceVal :=
{{.Config.Reporter.GRPC.BackendService.ToGoStringValue}}
- return NewGRPCReporter(logger, backendServiceVal, checkInterval,
connManager, cdsManager, pprofTaskManager, opts...)
+ profileFetchIntervalVal :=
{{.Config.Reporter.GRPC.ProfileFetchInterval.ToGoIntValue "the profile fetch
interval must be number"}}
+ profileFetchInterval := time.Second *
time.Duration(profileFetchIntervalVal)
+ return NewGRPCReporter(logger, backendServiceVal,
checkInterval,profileFetchInterval ,connManager, cdsManager, pprofTaskManager,
opts...)
}
`
diff --git a/tools/go-agent/tools/dst.go b/tools/go-agent/tools/dst.go
index fef5cfe..277cb28 100644
--- a/tools/go-agent/tools/dst.go
+++ b/tools/go-agent/tools/dst.go
@@ -119,6 +119,8 @@ func RemovePackageRef(parent dst.Node, current
*dst.SelectorExpr, inx int) {
p.Type = dst.NewIdent(current.Sel.Name)
case *dst.ArrayType:
p.Elt = dst.NewIdent(current.Sel.Name)
+ case *dst.ChanType:
+ p.Value = dst.NewIdent(current.Sel.Name)
case *dst.CallExpr:
p.Fun = dst.NewIdent(current.Sel.Name)
case *dst.KeyValueExpr: