You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/04/22 13:19:50 UTC
[skywalking-go] branch main updated: Support init the skywalking tracer in the application (#11)
This is an automated email from the ASF dual-hosted git repository.
wusheng 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 ec175e8 Support init the skywalking tracer in the application (#11)
ec175e8 is described below
commit ec175e8a50ad293385d4677aee409b90030b75aa
Author: mrproliu <74...@qq.com>
AuthorDate: Sat Apr 22 21:19:45 2023 +0800
Support init the skywalking tracer in the application (#11)
---
agent/core/compile.go | 5 +
plugins/core/operator/logger.go | 4 +
plugins/core/reporter/grpc_opts_enhance.go | 64 ++++++++
plugins/core/reporter/grpc_struct.go | 62 ++++++++
plugins/core/test_base.go | 2 +-
plugins/core/tool.go | 93 +++++++++++
plugins/core/tracer.go | 143 ++++++++++++++++-
plugins/core/tracing.go | 2 +-
reporter/grpc.go | 6 +-
.../core/operator/logger.go => reporter/imports.go | 13 +-
reporter/reporter.go | 2 +-
tools/go-agent/cmd/helper.go | 5 +-
tools/go-agent/cmd/main.go | 6 +
tools/go-agent/config/agent.default.yaml | 29 ++++
tools/go-agent/config/loader.go | 175 +++++++++++++++++++++
tools/go-agent/go.mod | 2 +-
tools/go-agent/instrument/agentcore/instrument.go | 87 +++++-----
tools/go-agent/instrument/entry/instrument.go | 94 +++++++++++
tools/go-agent/instrument/instrument.go | 8 +-
.../{framework => plugins}/enhance_instance.go | 2 +-
.../{framework => plugins}/enhance_method.go | 4 +-
.../{framework => plugins}/instrument.go | 4 +-
.../instrument/{framework => plugins}/register.go | 4 +-
.../{framework => plugins}/rewrite/context.go | 0
.../{framework => plugins}/rewrite/func.go | 0
.../{framework => plugins}/rewrite/import.go | 0
.../{framework => plugins}/rewrite/rewrite.go | 0
.../{framework => plugins}/rewrite/type.go | 0
.../{framework => plugins}/rewrite/var.go | 0
.../templates/method_inserts.tmpl | 0
.../templates/method_intercept_after.tmpl | 0
.../templates/method_intercept_before.tmpl | 0
tools/go-agent/instrument/reporter/instrument.go | 109 +++++++++++++
tools/go-agent/tools/copy.go | 73 +++++++++
34 files changed, 933 insertions(+), 65 deletions(-)
diff --git a/agent/core/compile.go b/agent/core/compile.go
index 9cbc9e3..599458c 100644
--- a/agent/core/compile.go
+++ b/agent/core/compile.go
@@ -21,9 +21,13 @@ import (
//go:nolint
_ "encoding/base64"
_ "fmt"
+ _ "log"
_ "math"
_ "math/rand"
+ _ "net"
+ _ "os"
_ "reflect"
+ _ "runtime"
_ "strconv"
_ "strings"
_ "sync"
@@ -33,6 +37,7 @@ import (
//go:nolint
_ "github.com/apache/skywalking-go/agent/core/operator"
_ "github.com/apache/skywalking-go/agent/core/tracing"
+ _ "github.com/apache/skywalking-go/log"
_ "github.com/apache/skywalking-go/reporter"
//go:nolint
diff --git a/plugins/core/operator/logger.go b/plugins/core/operator/logger.go
index 3534b1e..1945cee 100644
--- a/plugins/core/operator/logger.go
+++ b/plugins/core/operator/logger.go
@@ -17,8 +17,12 @@
package operator
+// LogOperator should be same with the log.Logger from the API of the library
type LogOperator interface {
+ Info(args ...interface{})
Infof(format string, args ...interface{})
+ Warn(args ...interface{})
Warnf(format string, args ...interface{})
+ Error(args ...interface{})
Errorf(format string, args ...interface{})
}
diff --git a/plugins/core/reporter/grpc_opts_enhance.go b/plugins/core/reporter/grpc_opts_enhance.go
new file mode 100644
index 0000000..4338b21
--- /dev/null
+++ b/plugins/core/reporter/grpc_opts_enhance.go
@@ -0,0 +1,64 @@
+// 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 reporter
+
+import (
+ "time"
+
+ "google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/metadata"
+
+ agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
+)
+
+var authKey = "Authentication"
+
+// WithCheckInterval setup service and endpoint registry check interval
+func WithCheckInterval(interval time.Duration) GRPCReporterOption {
+ return func(r *gRPCReporter) {
+ r.checkInterval = interval
+ }
+}
+
+// WithMaxSendQueueSize setup send span queue buffer length
+func WithMaxSendQueueSize(maxSendQueueSize int) GRPCReporterOption {
+ return func(r *gRPCReporter) {
+ r.sendCh = make(chan *agentv3.SegmentObject, maxSendQueueSize)
+ }
+}
+
+// WithTransportCredentials setup transport layer security
+func WithTransportCredentials(creds credentials.TransportCredentials) GRPCReporterOption {
+ return func(r *gRPCReporter) {
+ r.creds = creds
+ }
+}
+
+// WithAuthentication used Authentication for gRPC
+func WithAuthentication(auth string) GRPCReporterOption {
+ return func(r *gRPCReporter) {
+ r.md = metadata.New(map[string]string{authKey: auth})
+ }
+}
+
+// WithCDS setup Configuration Discovery Service to dynamic config
+func WithCDS(interval time.Duration) GRPCReporterOption {
+ return func(r *gRPCReporter) {
+ r.cdsInterval = interval
+ }
+}
diff --git a/plugins/core/reporter/grpc_struct.go b/plugins/core/reporter/grpc_struct.go
new file mode 100644
index 0000000..294a638
--- /dev/null
+++ b/plugins/core/reporter/grpc_struct.go
@@ -0,0 +1,62 @@
+// 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 reporter
+
+import (
+ "time"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/metadata"
+
+ configuration "skywalking.apache.org/repo/goapi/collect/agent/configuration/v3"
+ commonv3 "skywalking.apache.org/repo/goapi/collect/common/v3"
+ agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
+ managementv3 "skywalking.apache.org/repo/goapi/collect/management/v3"
+)
+
+//skywalking:nocopy
+
+// All struct are from the reporter package in the library, copy these files is works for compiler
+
+// nolint
+type Entity struct {
+ ServiceName string
+ ServiceInstanceName string
+ Props []*commonv3.KeyStringValuePair
+ Layer string
+}
+
+// nolint
+type gRPCReporter struct {
+ entity Entity
+ sendCh chan *agentv3.SegmentObject
+ conn *grpc.ClientConn
+ traceClient agentv3.TraceSegmentReportServiceClient
+ managementClient managementv3.ManagementServiceClient
+ checkInterval time.Duration
+ cdsInterval time.Duration
+ cdsClient configuration.ConfigurationDiscoveryServiceClient
+
+ md metadata.MD
+ creds credentials.TransportCredentials
+}
+
+// GRPCReporterOption allows for functional options to adjust behavior
+// of a gRPC reporter to be created by NewGRPCReporter
+type GRPCReporterOption func(r *gRPCReporter)
diff --git a/plugins/core/test_base.go b/plugins/core/test_base.go
index 8561ede..bdadee4 100644
--- a/plugins/core/test_base.go
+++ b/plugins/core/test_base.go
@@ -66,7 +66,7 @@ func NewStoreReporter() *StoreReporter {
return &StoreReporter{}
}
-func (r *StoreReporter) Boot(entity reporter.Entity, cdsWatchers []reporter.AgentConfigChangeWatcher) {
+func (r *StoreReporter) Boot(entity *reporter.Entity, cdsWatchers []reporter.AgentConfigChangeWatcher) {
}
func (r *StoreReporter) Send(spans []reporter.ReportedSpan) {
diff --git a/plugins/core/tool.go b/plugins/core/tool.go
index 1db067d..a3b5bc3 100644
--- a/plugins/core/tool.go
+++ b/plugins/core/tool.go
@@ -18,10 +18,16 @@
package core
import (
+ "net"
+ "os"
+ "runtime"
+ "strconv"
"strings"
"time"
"github.com/google/uuid"
+
+ commonv3 "skywalking.apache.org/repo/goapi/collect/common/v3"
)
// Millisecond converts time to unix millisecond
@@ -42,3 +48,90 @@ func UUID() (string, error) {
func GenerateGlobalID() (globalID string, err error) {
return UUID()
}
+
+func ProcessNo() string {
+ if os.Getpid() > 0 {
+ return strconv.Itoa(os.Getpid())
+ }
+ return ""
+}
+
+func HostName() string {
+ if hs, err := os.Hostname(); err == nil {
+ return hs
+ }
+ return "unknown"
+}
+
+func OSName() string {
+ return runtime.GOOS
+}
+
+func AllIPV4() (ipv4s []string) {
+ adders, err := net.InterfaceAddrs()
+ if err != nil {
+ return
+ }
+
+ for _, addr := range adders {
+ if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
+ if ipNet.IP.To4() != nil {
+ ipv4 := ipNet.IP.String()
+ if ipv4 == "127.0.0.1" || ipv4 == "localhost" {
+ continue
+ }
+ ipv4s = append(ipv4s, ipv4)
+ }
+ }
+ }
+ return
+}
+
+func IPV4() string {
+ ipv4s := AllIPV4()
+ if len(ipv4s) > 0 {
+ return ipv4s[0]
+ }
+ return "no-hostname"
+}
+
+func buildOSInfo() (props []*commonv3.KeyStringValuePair) {
+ processNo := ProcessNo()
+ if processNo != "" {
+ kv := &commonv3.KeyStringValuePair{
+ Key: "Process No.",
+ Value: processNo,
+ }
+ props = append(props, kv)
+ }
+
+ hostname := &commonv3.KeyStringValuePair{
+ Key: "hostname",
+ Value: HostName(),
+ }
+ props = append(props, hostname)
+
+ language := &commonv3.KeyStringValuePair{
+ Key: "language",
+ Value: "go",
+ }
+ props = append(props, language)
+
+ osName := &commonv3.KeyStringValuePair{
+ Key: "OS Name",
+ Value: OSName(),
+ }
+ props = append(props, osName)
+
+ ipv4s := AllIPV4()
+ if len(ipv4s) > 0 {
+ for _, ipv4 := range ipv4s {
+ kv := &commonv3.KeyStringValuePair{
+ Key: "ipv4",
+ Value: ipv4,
+ }
+ props = append(props, kv)
+ }
+ }
+ return props
+}
diff --git a/plugins/core/tracer.go b/plugins/core/tracer.go
index 3331a85..f249135 100644
--- a/plugins/core/tracer.go
+++ b/plugins/core/tracer.go
@@ -18,10 +18,19 @@
package core
import (
+ "fmt"
+ defLog "log"
+ "os"
+ "reflect"
+
+ "github.com/apache/skywalking-go/log"
"github.com/apache/skywalking-go/plugins/core/operator"
"github.com/apache/skywalking-go/reporter"
)
+// nolint
+var defaultLogPrefix = "skywalking-go "
+
type CorrelationConfig struct {
MaxKeyCount int
MaxValueSize int
@@ -34,11 +43,143 @@ type Tracer struct {
// 0 not init 1 init
initFlag int32
Sampler Sampler
- Log operator.LogOperator
+ Log *LogWrapper
// correlation *CorrelationConfig // temporarily disable, because haven't been implemented yet
cdsWatchers []reporter.AgentConfigChangeWatcher
}
+func (t *Tracer) Init(entity *reporter.Entity, rep reporter.Reporter, samp Sampler, logger log.Logger) error {
+ t.Service = entity.ServiceName
+ t.Instance = entity.ServiceInstanceName
+ t.Reporter = rep
+ t.Sampler = samp
+ if logger != nil && !reflect.ValueOf(logger).IsZero() {
+ t.Log.ChangeLogger(logger)
+ }
+ t.Reporter.Boot(entity, t.cdsWatchers)
+ t.initFlag = 1
+ return nil
+}
+
+func NewEntity(service, instanceEnvName, layer string) *reporter.Entity {
+ instanceName := os.Getenv(instanceEnvName)
+ if instanceName == "" {
+ id, err := UUID()
+ if err != nil {
+ panic(fmt.Sprintf("generate UUID failure: %v", err))
+ }
+ instanceName = id + "@" + IPV4()
+ }
+ propResult := buildOSInfo()
+ return &reporter.Entity{
+ ServiceName: service,
+ ServiceInstanceName: instanceName,
+ Props: propResult,
+ Layer: layer,
+ }
+}
+
+// create tracer when init the agent core
+// nolint
+func newTracer() *Tracer {
+ return &Tracer{
+ initFlag: 0,
+ Reporter: &emptyReporter{},
+ Sampler: NewConstSampler(false),
+ Log: &LogWrapper{newDefaultLogger()},
+ cdsWatchers: make([]reporter.AgentConfigChangeWatcher, 0),
+ }
+}
+
func (t *Tracer) InitSuccess() bool {
return t.initFlag == 1
}
+
+// nolint
+type emptyReporter struct{}
+
+// nolint
+func (e *emptyReporter) Boot(entity *reporter.Entity, cdsWatchers []reporter.AgentConfigChangeWatcher) {
+}
+
+// nolint
+func (e *emptyReporter) Send(spans []reporter.ReportedSpan) {
+}
+
+// nolint
+func (e *emptyReporter) Close() {
+}
+
+type LogWrapper struct {
+ Logger operator.LogOperator
+}
+
+func (l *LogWrapper) ChangeLogger(logger operator.LogOperator) {
+ l.Logger = logger
+}
+
+func (l *LogWrapper) Info(args ...interface{}) {
+ l.Logger.Info(args...)
+}
+
+func (l *LogWrapper) Infof(format string, args ...interface{}) {
+ l.Logger.Infof(format, args...)
+}
+
+func (l *LogWrapper) Warn(args ...interface{}) {
+ l.Logger.Warn(args...)
+}
+
+func (l *LogWrapper) Warnf(format string, args ...interface{}) {
+ l.Logger.Warnf(format, args...)
+}
+
+func (l *LogWrapper) Error(args ...interface{}) {
+ l.Logger.Error(args...)
+}
+
+func (l *LogWrapper) Errorf(format string, args ...interface{}) {
+ l.Logger.Errorf(format, args...)
+}
+
+// nolint
+type defaultLogger struct {
+ log *defLog.Logger
+}
+
+// nolint
+func newDefaultLogger() *defaultLogger {
+ return &defaultLogger{
+ log: defLog.New(os.Stderr, defaultLogPrefix, defLog.LstdFlags),
+ }
+}
+
+// nolint
+func (d *defaultLogger) Info(args ...interface{}) {
+ d.log.Print(args...)
+}
+
+// nolint
+func (d *defaultLogger) Infof(format string, args ...interface{}) {
+ d.log.Printf(format, args...)
+}
+
+// nolint
+func (d *defaultLogger) Warn(args ...interface{}) {
+ d.log.Print(args...)
+}
+
+// nolint
+func (d *defaultLogger) Warnf(format string, args ...interface{}) {
+ d.log.Printf(format, args...)
+}
+
+// nolint
+func (d *defaultLogger) Error(args ...interface{}) {
+ d.log.Print(args...)
+}
+
+// nolint
+func (d *defaultLogger) Errorf(format string, args ...interface{}) {
+ d.log.Printf(format, args...)
+}
diff --git a/plugins/core/tracing.go b/plugins/core/tracing.go
index 1f4c383..5ae1fe6 100644
--- a/plugins/core/tracing.go
+++ b/plugins/core/tracing.go
@@ -41,7 +41,7 @@ func (t *Tracer) Logger() interface{} {
func (t *Tracer) CreateEntrySpan(operationName string, extractor interface{}, opts ...interface{}) (s interface{}, err error) {
ctx, tracingSpan, noop := t.createNoop()
if noop {
- return s, nil
+ return tracingSpan, nil
}
defer func() {
saveSpanToActiveIfNotError(ctx, s, err)
diff --git a/reporter/grpc.go b/reporter/grpc.go
index 63eb2b5..2d3c782 100644
--- a/reporter/grpc.go
+++ b/reporter/grpc.go
@@ -77,7 +77,7 @@ func NewGRPCReporter(logger log.Logger, serverAddr string, opts ...GRPCReporterO
}
type gRPCReporter struct {
- entity Entity
+ entity *Entity
logger log.Logger
sendCh chan *agentv3.SegmentObject
conn *grpc.ClientConn
@@ -95,7 +95,7 @@ type gRPCReporter struct {
bootFlag bool
}
-func (r *gRPCReporter) Boot(entity Entity, cdsWatchers []AgentConfigChangeWatcher) {
+func (r *gRPCReporter) Boot(entity *Entity, cdsWatchers []AgentConfigChangeWatcher) {
r.entity = entity
r.initSendPipeline()
r.check()
@@ -114,7 +114,7 @@ func (r *gRPCReporter) Send(spans []ReportedSpan) {
TraceId: rootCtx.GetTraceID(),
TraceSegmentId: rootCtx.GetSegmentID(),
Spans: make([]*agentv3.SpanObject, spanSize),
- Service: r.entity.ServiceInstanceName,
+ Service: r.entity.ServiceName,
ServiceInstance: r.entity.ServiceInstanceName,
}
for i, s := range spans {
diff --git a/plugins/core/operator/logger.go b/reporter/imports.go
similarity index 82%
copy from plugins/core/operator/logger.go
copy to reporter/imports.go
index 3534b1e..87c2170 100644
--- a/plugins/core/operator/logger.go
+++ b/reporter/imports.go
@@ -15,10 +15,11 @@
// specific language governing permissions and limitations
// under the License.
-package operator
+package reporter
-type LogOperator interface {
- Infof(format string, args ...interface{})
- Warnf(format string, args ...interface{})
- Errorf(format string, args ...interface{})
-}
+import (
+ // imports required packages for gRPC reporter
+ _ "fmt"
+ _ "os"
+ _ "strconv"
+)
diff --git a/reporter/reporter.go b/reporter/reporter.go
index 679777f..b9e2542 100644
--- a/reporter/reporter.go
+++ b/reporter/reporter.go
@@ -88,7 +88,7 @@ type Entity struct {
}
type Reporter interface {
- Boot(entity Entity, cdsWatchers []AgentConfigChangeWatcher)
+ Boot(entity *Entity, cdsWatchers []AgentConfigChangeWatcher)
Send(spans []ReportedSpan)
Close()
}
diff --git a/tools/go-agent/cmd/helper.go b/tools/go-agent/cmd/helper.go
index 751d163..f3cccff 100644
--- a/tools/go-agent/cmd/helper.go
+++ b/tools/go-agent/cmd/helper.go
@@ -23,8 +23,9 @@ import (
)
type EnhancementToolFlags struct {
- Help bool `swflag:"-h"`
- Debug string `swflag:"-debug"`
+ Help bool `swflag:"-h"`
+ Debug string `swflag:"-debug"`
+ Config string `swflag:"-config"`
}
func PrintUsageWithExit() {
diff --git a/tools/go-agent/cmd/main.go b/tools/go-agent/cmd/main.go
index 85b1148..2c721af 100644
--- a/tools/go-agent/cmd/main.go
+++ b/tools/go-agent/cmd/main.go
@@ -23,6 +23,7 @@ import (
"os"
"os/exec"
+ "github.com/apache/skywalking-go/tools/go-agent/config"
"github.com/apache/skywalking-go/tools/go-agent/instrument"
"github.com/apache/skywalking-go/tools/go-agent/instrument/api"
"github.com/apache/skywalking-go/tools/go-agent/tools"
@@ -59,6 +60,11 @@ func main() {
return
}
+ // loading config
+ if err1 := config.LoadConfig(toolFlags.Config); err1 != nil {
+ log.Fatalf("loading config file error: %s", err1)
+ }
+
// parse the args
compileOptions := &api.CompileOptions{}
if _, err = tools.ParseFlags(compileOptions, args); err != nil {
diff --git a/tools/go-agent/config/agent.default.yaml b/tools/go-agent/config/agent.default.yaml
new file mode 100644
index 0000000..502e64b
--- /dev/null
+++ b/tools/go-agent/config/agent.default.yaml
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+agent:
+ service_name: ${SW_AGENT_NAME:Your_ApplicationName}
+ instance_env_name: SW_AGENT_INSTANCE_NAME
+ layer: GENERAL
+ sampler: ${SW_AGENT_SAMPLE:1}
+
+reporter:
+ grpc:
+ backend_service: ${SW_AGENT_REPORTER_GRPC_BACKEND_SERVICE:127.0.0.1:11800}
+ max_send_queue: ${SW_AGENT_REPORTER_GRPC_MAX_SEND_QUEUE:5000}
diff --git a/tools/go-agent/config/loader.go b/tools/go-agent/config/loader.go
new file mode 100644
index 0000000..f0b5e19
--- /dev/null
+++ b/tools/go-agent/config/loader.go
@@ -0,0 +1,175 @@
+// 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 config
+
+import (
+ "embed"
+ "fmt"
+ "os"
+ "reflect"
+ "regexp"
+ "strings"
+
+ "gopkg.in/yaml.v3"
+)
+
+//go:embed agent.default.yaml
+var defaultAgentFS embed.FS
+
+var config *Config
+
+var EnvRegularRegex = regexp.MustCompile(`\${(?P<ENV>[_A-Z0-9]+):(?P<DEF>.*)}`)
+
+type Config struct {
+ Agent Agent `yaml:"agent"`
+ Reporter Reporter `yaml:"reporter"`
+}
+
+type Agent struct {
+ ServiceName StringValue `yaml:"service_name"`
+ InstanceEnvName StringValue `yaml:"instance_env_name"`
+ Sampler StringValue `yaml:"sampler"`
+ Layer StringValue `yaml:"layer"`
+}
+
+type Reporter struct {
+ GRPC GRPCReporter `yaml:"grpc"`
+}
+
+type GRPCReporter struct {
+ BackendService StringValue `yaml:"backend_service"`
+ MaxSendQueue StringValue `yaml:"max_send_queue"`
+}
+
+func LoadConfig(path string) error {
+ // load the default config
+ defaultConfig, err := defaultAgentFS.ReadFile("agent.default.yaml")
+ if err != nil {
+ return err
+ }
+ if err1 := yaml.Unmarshal(defaultConfig, &config); err1 != nil {
+ return err1
+ }
+
+ // if the path defined, then merge this two files
+ if path == "" {
+ return nil
+ }
+ definedContent, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ userConfig := &Config{}
+ if err := yaml.Unmarshal(definedContent, userConfig); err != nil {
+ return err
+ }
+ config.overwriteFrom(userConfig)
+
+ return nil
+}
+
+func GetConfig() *Config {
+ return config
+}
+
+type StringValue struct {
+ EnvKey string
+ Default string
+}
+
+func (s *StringValue) UnmarshalYAML(value *yaml.Node) error {
+ var val string
+ if e := value.Decode(&val); e != nil {
+ return e
+ }
+
+ groups := EnvRegularRegex.FindStringSubmatch(val)
+ if len(groups) == 0 {
+ s.Default = val
+ return nil
+ }
+
+ s.EnvKey = groups[1]
+ s.Default = groups[2]
+ return nil
+}
+
+func (s *StringValue) ToGoStringValue() string {
+ return strings.ReplaceAll(fmt.Sprintf(`func() string {
+ if "%s" == "" { return "%s"}
+ tmpValue := os.Getenv("%s")
+ if tmpValue == "" { return "%s"}
+ return tmpValue
+}()`, s.EnvKey, s.Default, s.EnvKey, s.Default), "\n", ";")
+}
+
+func (s *StringValue) ToGoIntValue(errorMessage string) string {
+ return strings.ReplaceAll(fmt.Sprintf(`func() int {
+ if "%s" == "" {return %s}
+ tmpValue := os.Getenv("%s")
+ if tmpValue == "" {return %s}
+ res, err := strconv.Atoi(tmpValue)
+ if err != nil { panic(fmt.Errorf("%s", err))}
+ return res
+}()`,
+ s.EnvKey, s.Default, s.EnvKey, s.Default, errorMessage), "\n", ";")
+}
+
+func (s *StringValue) ToGoFloatValue(errorMessage string) string {
+ return strings.ReplaceAll(fmt.Sprintf(`func() float64 {
+ if "%s" == "" {return %s}
+ tmpValue := os.Getenv("%s")
+ if tmpValue == "" {return %s}
+ res, err := strconv.ParseFloat(tmpValue, 64)
+ if err != nil { panic(fmt.Errorf("%s", err))}
+ return res
+}()`,
+ s.EnvKey, s.Default, s.EnvKey, s.Default, errorMessage), "\n", ";")
+}
+
+func (s *StringValue) overwriteFrom(other StringValue) {
+ if other.EnvKey != "" {
+ s.EnvKey = other.EnvKey
+ }
+ if other.Default != "" {
+ s.Default = other.Default
+ }
+}
+
+func (c *Config) overwriteFrom(other *Config) {
+ c1Value := reflect.ValueOf(&c).Elem()
+ c2Value := reflect.ValueOf(&other).Elem()
+ combineConfigFields(c1Value, c2Value)
+}
+
+func combineConfigFields(field1, field2 reflect.Value) {
+ if field1.Type() != field2.Type() {
+ panic("config are not the same")
+ }
+
+ if field1.Kind() == reflect.Struct {
+ if s, ok := field1.Addr().Interface().(StringValue); ok {
+ s2 := field2.Addr().Interface().(StringValue)
+ s.overwriteFrom(s2)
+ } else {
+ for i := 0; i < field1.NumField(); i++ {
+ combineConfigFields(field1.Field(i), field2.Field(i))
+ }
+ }
+ }
+}
diff --git a/tools/go-agent/go.mod b/tools/go-agent/go.mod
index 4413213..0ded49d 100644
--- a/tools/go-agent/go.mod
+++ b/tools/go-agent/go.mod
@@ -8,6 +8,7 @@ require (
github.com/dave/dst v0.27.2
github.com/sirupsen/logrus v1.9.0
golang.org/x/text v0.8.0
+ gopkg.in/yaml.v3 v3.0.1
)
require (
@@ -41,7 +42,6 @@ require (
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/protobuf v1.29.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
skywalking.apache.org/repo/goapi v0.0.0-20230314034821-0c5a44bb767a // indirect
)
diff --git a/tools/go-agent/instrument/agentcore/instrument.go b/tools/go-agent/instrument/agentcore/instrument.go
index 7c589db..6cb4184 100644
--- a/tools/go-agent/instrument/agentcore/instrument.go
+++ b/tools/go-agent/instrument/agentcore/instrument.go
@@ -18,18 +18,19 @@
package agentcore
import (
- "bytes"
+ "html"
"io/fs"
"path/filepath"
"strings"
"github.com/apache/skywalking-go/plugins/core"
+ "github.com/apache/skywalking-go/tools/go-agent/config"
"github.com/apache/skywalking-go/tools/go-agent/instrument/api"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/reporter"
"github.com/apache/skywalking-go/tools/go-agent/instrument/runtime"
"github.com/apache/skywalking-go/tools/go-agent/tools"
"github.com/dave/dst"
- "github.com/dave/dst/decorator"
"github.com/dave/dst/dstutil"
)
@@ -84,49 +85,18 @@ func (i *Instrument) WriteExtraFiles(dir string) ([]string, error) {
if sub == "" {
sub = "."
}
- files, err := core.FS.ReadDir(sub)
- if err != nil {
- return nil, err
- }
pkgUpdates := make(map[string]string)
for _, p := range CopiedSubPackages {
pkgUpdates[filepath.Join(EnhanceFromBasePackage, p)] = filepath.Join(EnhanceBasePackage, p)
}
- for _, f := range files {
- if !strings.HasSuffix(f.Name(), ".go") {
- continue
- }
- if strings.HasSuffix(f.Name(), "_test.go") {
- continue
- }
-
- readFile, err := fs.ReadFile(core.FS, filepath.Join(sub, f.Name()))
- if err != nil {
- return nil, err
- }
-
- // ignore nocopy files
- if bytes.Contains(readFile, []byte("//skywalking:nocopy")) {
- continue
- }
-
- parse, err := decorator.Parse(readFile)
- if err != nil {
- return nil, err
- }
- debugInfo, err := i.buildDSTDebugInfo(f)
- if err != nil {
- return nil, err
- }
-
- tools.ChangePackageImportPath(parse, pkgUpdates)
- copiedFilePath := filepath.Join(dir, f.Name())
- if err := tools.WriteDSTFile(copiedFilePath, parse, debugInfo); err != nil {
- return nil, err
- }
- results = append(results, copiedFilePath)
+ copiedFiles, err := tools.CopyGoFiles(core.FS, sub, dir, i.buildDSTDebugInfo, func(file *dst.File) {
+ tools.ChangePackageImportPath(file, pkgUpdates)
+ })
+ if err != nil {
+ return nil, err
}
+ results = append(results, copiedFiles...)
// write extra file to link the operator and TLS methods
if sub == "." {
@@ -135,6 +105,12 @@ func (i *Instrument) WriteExtraFiles(dir string) ([]string, error) {
return nil, err
}
results = append(results, file)
+
+ file1, err := i.writeTracerInitLink(dir)
+ if err != nil {
+ return nil, err
+ }
+ results = append(results, file1)
}
return results, nil
@@ -148,6 +124,37 @@ func (i *Instrument) buildDSTDebugInfo(entry fs.DirEntry) (*tools.DebugInfo, err
return tools.BuildDSTDebugInfo(debugPath, nil)
}
+func (i *Instrument) writeTracerInitLink(dir string) (string, error) {
+ return tools.WriteFile(dir, "tracer_init.go", html.UnescapeString(tools.ExecuteTemplate(`package core
+
+import (
+ "github.com/apache/skywalking-go/reporter"
+ "fmt"
+ "os"
+ "strconv"
+)
+
+func (t *Tracer) InitTracer(extend map[string]interface{}) {
+ rep, err := reporter.{{.GRPCReporterFuncName}}(t.Log)
+ if err != nil {
+ t.Log.Errorf("cannot initialize the reporter: %v", err)
+ return
+ }
+ entity := NewEntity({{.Config.Agent.ServiceName.ToGoStringValue}}, {{.Config.Agent.InstanceEnvName.ToGoStringValue}},
+ {{.Config.Agent.Layer.ToGoStringValue}})
+ samp := NewDynamicSampler({{.Config.Agent.Sampler.ToGoFloatValue "loading the agent sampler error"}}, t)
+ if err := t.Init(entity, rep, samp, nil); err != nil {
+ t.Log.Errorf("cannot initialize the SkyWalking Tracer: %v", err)
+ }
+}`, struct {
+ GRPCReporterFuncName string
+ Config *config.Config
+ }{
+ GRPCReporterFuncName: reporter.GRPCInitFuncName,
+ Config: config.GetConfig(),
+ })))
+}
+
func (i *Instrument) writeLinkerFile(dir string) (string, error) {
return tools.WriteFile(dir, "runtime_linker.go", tools.ExecuteTemplate(`package core
@@ -175,7 +182,7 @@ func init() {
if {{.SetGlobalOperatorLinkMethod}} != nil && {{.GetGlobalOperatorLinkMethod}} != nil {
SetGlobalOperator = {{.SetGlobalOperatorLinkMethod}}
GetGlobalOperator = {{.GetGlobalOperatorLinkMethod}}
- SetGlobalOperator(&Tracer{initFlag: 1, Sampler: NewConstSampler(true)})
+ SetGlobalOperator(newTracer()) // setting the global tracer when init the agent core
}
}
`, struct {
diff --git a/tools/go-agent/instrument/entry/instrument.go b/tools/go-agent/instrument/entry/instrument.go
new file mode 100644
index 0000000..374a4a4
--- /dev/null
+++ b/tools/go-agent/instrument/entry/instrument.go
@@ -0,0 +1,94 @@
+// 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 entry
+
+import (
+ "github.com/apache/skywalking-go/tools/go-agent/config"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/api"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/plugins/rewrite"
+ "github.com/apache/skywalking-go/tools/go-agent/tools"
+
+ "github.com/dave/dst"
+ "github.com/dave/dst/dstutil"
+)
+
+type Instrument struct {
+ hasFound bool
+}
+
+func NewInstrument() *Instrument {
+ return &Instrument{}
+}
+
+func (i *Instrument) CouldHandle(opts *api.CompileOptions) bool {
+ return opts.Package == "main"
+}
+
+func (i *Instrument) FilterAndEdit(path string, cursor *dstutil.Cursor, allFiles []*dst.File) bool {
+ if i.hasFound {
+ return false
+ }
+ i.hasFound = true
+ return true
+}
+
+func (i *Instrument) AfterEnhanceFile(fromPath, newPath string) error {
+ return nil
+}
+
+func (i *Instrument) WriteExtraFiles(dir string) ([]string, error) {
+ file, err := tools.WriteFile(dir, "skywalking_init.go", tools.ExecuteTemplate(`package main
+
+import (
+ _ "unsafe"
+)
+
+//go:linkname {{.GetGlobalOperatorLinkMethod}} {{.GetGlobalOperatorLinkMethod}}
+var {{.GetGlobalOperatorLinkMethod}} func() interface{}
+
+type skywalkingTracerInitiator interface {
+ InitTracer(map[string]interface{})
+}
+
+func init() {
+ if {{.GetGlobalOperatorLinkMethod}} != nil {
+ op := {{.GetGlobalOperatorLinkMethod}}()
+ if op == nil {
+ return
+ }
+ tracer, ok := op.(skywalkingTracerInitiator)
+ if !ok {
+ return
+ }
+ tracer.InitTracer(nil)
+ }
+}
+`, struct {
+ GetGlobalOperatorLinkMethod string
+ Config *config.Config
+ }{
+ GetGlobalOperatorLinkMethod: rewrite.GlobalOperatorLinkGetMethodName,
+ Config: config.GetConfig(),
+ }))
+ if err != nil {
+ return nil, err
+ }
+ result := make([]string, 0)
+ result = append(result, file)
+ return result, nil
+}
diff --git a/tools/go-agent/instrument/instrument.go b/tools/go-agent/instrument/instrument.go
index 4d2b501..0c70d60 100644
--- a/tools/go-agent/instrument/instrument.go
+++ b/tools/go-agent/instrument/instrument.go
@@ -31,7 +31,9 @@ import (
"github.com/apache/skywalking-go/tools/go-agent/instrument/agentcore"
"github.com/apache/skywalking-go/tools/go-agent/instrument/api"
- "github.com/apache/skywalking-go/tools/go-agent/instrument/framework"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/entry"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/plugins"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/reporter"
"github.com/apache/skywalking-go/tools/go-agent/instrument/runtime"
"github.com/apache/skywalking-go/tools/go-agent/tools"
)
@@ -39,7 +41,9 @@ import (
var instruments = []api.Instrument{
runtime.NewInstrument(),
agentcore.NewInstrument(),
- framework.NewInstrument(),
+ reporter.NewGRPCInstrument(),
+ entry.NewInstrument(),
+ plugins.NewInstrument(),
}
func Execute(opts *api.CompileOptions, args []string) ([]string, error) {
diff --git a/tools/go-agent/instrument/framework/enhance_instance.go b/tools/go-agent/instrument/plugins/enhance_instance.go
similarity index 99%
rename from tools/go-agent/instrument/framework/enhance_instance.go
rename to tools/go-agent/instrument/plugins/enhance_instance.go
index 990618b..e3b6ab2 100644
--- a/tools/go-agent/instrument/framework/enhance_instance.go
+++ b/tools/go-agent/instrument/plugins/enhance_instance.go
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package framework
+package plugins
import (
"fmt"
diff --git a/tools/go-agent/instrument/framework/enhance_method.go b/tools/go-agent/instrument/plugins/enhance_method.go
similarity index 98%
rename from tools/go-agent/instrument/framework/enhance_method.go
rename to tools/go-agent/instrument/plugins/enhance_method.go
index 64674ce..ab64320 100644
--- a/tools/go-agent/instrument/framework/enhance_method.go
+++ b/tools/go-agent/instrument/plugins/enhance_method.go
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package framework
+package plugins
import (
"fmt"
@@ -25,7 +25,7 @@ import (
"github.com/apache/skywalking-go/plugins/core/instrument"
"github.com/apache/skywalking-go/tools/go-agent/instrument/agentcore"
- "github.com/apache/skywalking-go/tools/go-agent/instrument/framework/rewrite"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/plugins/rewrite"
"github.com/apache/skywalking-go/tools/go-agent/tools"
"github.com/dave/dst"
diff --git a/tools/go-agent/instrument/framework/instrument.go b/tools/go-agent/instrument/plugins/instrument.go
similarity index 99%
rename from tools/go-agent/instrument/framework/instrument.go
rename to tools/go-agent/instrument/plugins/instrument.go
index 55dedd5..de1ac90 100644
--- a/tools/go-agent/instrument/framework/instrument.go
+++ b/tools/go-agent/instrument/plugins/instrument.go
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package framework
+package plugins
import (
"bytes"
@@ -29,7 +29,7 @@ import (
"github.com/apache/skywalking-go/plugins/core"
"github.com/apache/skywalking-go/plugins/core/instrument"
"github.com/apache/skywalking-go/tools/go-agent/instrument/api"
- "github.com/apache/skywalking-go/tools/go-agent/instrument/framework/rewrite"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/plugins/rewrite"
"github.com/apache/skywalking-go/tools/go-agent/tools"
"github.com/dave/dst"
diff --git a/tools/go-agent/instrument/framework/register.go b/tools/go-agent/instrument/plugins/register.go
similarity index 95%
rename from tools/go-agent/instrument/framework/register.go
rename to tools/go-agent/instrument/plugins/register.go
index 0c0bcf1..6caf205 100644
--- a/tools/go-agent/instrument/framework/register.go
+++ b/tools/go-agent/instrument/plugins/register.go
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-package framework
+package plugins
import (
"github.com/apache/skywalking-go/plugins/core/instrument"
@@ -25,7 +25,7 @@ import (
var instruments = make([]instrument.Instrument, 0)
func init() {
- // register the framework instrument
+ // register the plugins instrument
registerFramework(ginv2.NewInstrument())
}
diff --git a/tools/go-agent/instrument/framework/rewrite/context.go b/tools/go-agent/instrument/plugins/rewrite/context.go
similarity index 100%
rename from tools/go-agent/instrument/framework/rewrite/context.go
rename to tools/go-agent/instrument/plugins/rewrite/context.go
diff --git a/tools/go-agent/instrument/framework/rewrite/func.go b/tools/go-agent/instrument/plugins/rewrite/func.go
similarity index 100%
rename from tools/go-agent/instrument/framework/rewrite/func.go
rename to tools/go-agent/instrument/plugins/rewrite/func.go
diff --git a/tools/go-agent/instrument/framework/rewrite/import.go b/tools/go-agent/instrument/plugins/rewrite/import.go
similarity index 100%
rename from tools/go-agent/instrument/framework/rewrite/import.go
rename to tools/go-agent/instrument/plugins/rewrite/import.go
diff --git a/tools/go-agent/instrument/framework/rewrite/rewrite.go b/tools/go-agent/instrument/plugins/rewrite/rewrite.go
similarity index 100%
rename from tools/go-agent/instrument/framework/rewrite/rewrite.go
rename to tools/go-agent/instrument/plugins/rewrite/rewrite.go
diff --git a/tools/go-agent/instrument/framework/rewrite/type.go b/tools/go-agent/instrument/plugins/rewrite/type.go
similarity index 100%
rename from tools/go-agent/instrument/framework/rewrite/type.go
rename to tools/go-agent/instrument/plugins/rewrite/type.go
diff --git a/tools/go-agent/instrument/framework/rewrite/var.go b/tools/go-agent/instrument/plugins/rewrite/var.go
similarity index 100%
rename from tools/go-agent/instrument/framework/rewrite/var.go
rename to tools/go-agent/instrument/plugins/rewrite/var.go
diff --git a/tools/go-agent/instrument/framework/templates/method_inserts.tmpl b/tools/go-agent/instrument/plugins/templates/method_inserts.tmpl
similarity index 100%
rename from tools/go-agent/instrument/framework/templates/method_inserts.tmpl
rename to tools/go-agent/instrument/plugins/templates/method_inserts.tmpl
diff --git a/tools/go-agent/instrument/framework/templates/method_intercept_after.tmpl b/tools/go-agent/instrument/plugins/templates/method_intercept_after.tmpl
similarity index 100%
rename from tools/go-agent/instrument/framework/templates/method_intercept_after.tmpl
rename to tools/go-agent/instrument/plugins/templates/method_intercept_after.tmpl
diff --git a/tools/go-agent/instrument/framework/templates/method_intercept_before.tmpl b/tools/go-agent/instrument/plugins/templates/method_intercept_before.tmpl
similarity index 100%
rename from tools/go-agent/instrument/framework/templates/method_intercept_before.tmpl
rename to tools/go-agent/instrument/plugins/templates/method_intercept_before.tmpl
diff --git a/tools/go-agent/instrument/reporter/instrument.go b/tools/go-agent/instrument/reporter/instrument.go
new file mode 100644
index 0000000..c05caf8
--- /dev/null
+++ b/tools/go-agent/instrument/reporter/instrument.go
@@ -0,0 +1,109 @@
+// 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 reporter
+
+import (
+ "html"
+ "io/fs"
+ "path/filepath"
+
+ "github.com/apache/skywalking-go/plugins/core"
+ "github.com/apache/skywalking-go/tools/go-agent/config"
+ "github.com/apache/skywalking-go/tools/go-agent/instrument/api"
+ "github.com/apache/skywalking-go/tools/go-agent/tools"
+
+ "github.com/dave/dst"
+ "github.com/dave/dst/dstutil"
+)
+
+var GRPCInitFuncName = "GRPCReporterInit"
+
+type GRPCInstrument struct {
+ hasToEnhance bool
+ compileOpts *api.CompileOptions
+}
+
+func NewGRPCInstrument() *GRPCInstrument {
+ return &GRPCInstrument{}
+}
+
+func (i *GRPCInstrument) CouldHandle(opts *api.CompileOptions) bool {
+ i.compileOpts = opts
+ return opts.Package == "github.com/apache/skywalking-go/reporter"
+}
+
+func (i *GRPCInstrument) FilterAndEdit(path string, cursor *dstutil.Cursor, allFiles []*dst.File) bool {
+ if i.hasToEnhance {
+ return false
+ }
+ i.hasToEnhance = true
+ return true
+}
+
+func (i *GRPCInstrument) AfterEnhanceFile(fromPath, newPath string) error {
+ return nil
+}
+
+func (i *GRPCInstrument) WriteExtraFiles(dir string) ([]string, error) {
+ // copy gRPC reporter enhance files
+ results := make([]string, 0)
+ copiedFiles, err := tools.CopyGoFiles(core.FS, "reporter", dir, func(entry fs.DirEntry) (*tools.DebugInfo, error) {
+ if i.compileOpts.DebugDir == "" {
+ return nil, nil
+ }
+ debugPath := filepath.Join(i.compileOpts.DebugDir, "reporter", entry.Name())
+ return tools.BuildDSTDebugInfo(debugPath, nil)
+ }, func(file *dst.File) {
+ })
+ if err != nil {
+ return nil, err
+ }
+ results = append(results, copiedFiles...)
+
+ // generate the file for export the reporter
+ file, err := i.generateReporterInitFile(dir)
+ if err != nil {
+ return nil, err
+ }
+ results = append(results, file)
+
+ return results, nil
+}
+
+func (i *GRPCInstrument) generateReporterInitFile(dir string) (string, error) {
+ return tools.WriteFile(dir, "grpc_init.go", html.UnescapeString(tools.ExecuteTemplate(`package reporter
+
+import (
+ "github.com/apache/skywalking-go/log"
+ "fmt"
+ "strconv"
+ "os"
+)
+
+func {{.InitFuncName}}(logger log.Logger) (Reporter, error) {
+ return NewGRPCReporter(logger, {{.Config.Reporter.GRPC.BackendService.ToGoStringValue}},
+ WithMaxSendQueueSize({{.Config.Reporter.GRPC.MaxSendQueue.ToGoIntValue "the GRPC reporter max queue size must be number"}}))
+}
+`, struct {
+ InitFuncName string
+ Config *config.Config
+ }{
+ InitFuncName: GRPCInitFuncName,
+ Config: config.GetConfig(),
+ })))
+}
diff --git a/tools/go-agent/tools/copy.go b/tools/go-agent/tools/copy.go
new file mode 100644
index 0000000..0ceeb1a
--- /dev/null
+++ b/tools/go-agent/tools/copy.go
@@ -0,0 +1,73 @@
+// 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 tools
+
+import (
+ "bytes"
+ "io/fs"
+ "path/filepath"
+ "strings"
+
+ "github.com/dave/dst"
+ "github.com/dave/dst/decorator"
+)
+
+func CopyGoFiles(fromFS fs.ReadDirFS, fromDir, targetDir string,
+ debugInfoBuilder func(entry fs.DirEntry) (*DebugInfo, error),
+ peek func(file *dst.File)) ([]string, error) {
+ results := make([]string, 0)
+ files, err := fromFS.ReadDir(fromDir)
+ if err != nil {
+ return nil, err
+ }
+ for _, f := range files {
+ if !strings.HasSuffix(f.Name(), ".go") {
+ continue
+ }
+ if strings.HasSuffix(f.Name(), "_test.go") {
+ continue
+ }
+
+ readFile, err := fs.ReadFile(fromFS, filepath.Join(fromDir, f.Name()))
+ if err != nil {
+ return nil, err
+ }
+
+ // ignore nocopy files
+ if bytes.Contains(readFile, []byte("//skywalking:nocopy")) {
+ continue
+ }
+
+ parse, err := decorator.Parse(readFile)
+ if err != nil {
+ return nil, err
+ }
+ debugInfo, err := debugInfoBuilder(f)
+ if err != nil {
+ return nil, err
+ }
+
+ peek(parse)
+ copiedFilePath := filepath.Join(targetDir, f.Name())
+ if err := WriteDSTFile(copiedFilePath, parse, debugInfo); err != nil {
+ return nil, err
+ }
+ results = append(results, copiedFilePath)
+ }
+ return results, nil
+}