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 512efb2 Support log report to the backend (#68)
512efb2 is described below
commit 512efb2f1347f36e66cb827266c77e73ae70773d
Author: mrproliu <[email protected]>
AuthorDate: Tue Jul 11 05:07:59 2023 +0000
Support log report to the backend (#68)
---
.github/workflows/plugin-tests.yaml | 2 +
CHANGES.md | 5 +
go.work | 2 +
plugins/core/logreport.go | 87 +++++++++
plugins/core/operator/common.go | 13 +-
plugins/core/operator/logger.go | 4 +
plugins/core/reporter/api.go | 2 +
plugins/core/reporter/grpc/grpc.go | 46 +++++
plugins/core/span_default.go | 11 ++
plugins/core/span_noop.go | 8 +
plugins/core/test_base.go | 7 +
plugins/core/tracer.go | 6 +
plugins/go-redisv9/go.mod | 5 +-
plugins/go-redisv9/go.sum | 15 --
plugins/gorm/go.mod | 2 +-
plugins/gorm/go.sum | 2 +-
plugins/runtimemetrics/instrument.go | 2 +-
test/plugins/scenarios/logrus/bin/startup.sh | 24 +++
test/plugins/scenarios/logrus/config/excepted.yml | 67 +++++++
test/plugins/scenarios/logrus/go.mod | 8 +
test/plugins/scenarios/logrus/go.sum | 11 ++
test/plugins/scenarios/logrus/main.go | 67 +++++++
test/plugins/scenarios/logrus/plugin.yml | 30 ++++
test/plugins/scenarios/zap/bin/startup.sh | 24 +++
test/plugins/scenarios/zap/config/excepted.yml | 67 +++++++
test/plugins/scenarios/zap/go.mod | 3 +
test/plugins/scenarios/zap/go.sum | 0
test/plugins/scenarios/zap/main.go | 66 +++++++
test/plugins/scenarios/zap/plugin.yml | 34 ++++
tools/go-agent/config/agent.default.yaml | 5 +
tools/go-agent/config/loader.go | 30 +++-
tools/go-agent/instrument/consts/operator.go | 20 +--
tools/go-agent/instrument/consts/tls.go | 4 +-
tools/go-agent/instrument/logger/context.go | 70 +++++++-
tools/go-agent/instrument/logger/context_test.go | 17 +-
tools/go-agent/instrument/logger/frameworks/api.go | 33 +++-
.../instrument/logger/frameworks/logrus.go | 11 +-
.../instrument/logger/frameworks/logrus_adapt.go | 4 +-
.../instrument/logger/frameworks/logrus_format.go | 26 ++-
.../logger/frameworks/templates/init.tmpl | 36 +++-
tools/go-agent/instrument/logger/frameworks/zap.go | 194 +++++++++++++--------
.../instrument/logger/frameworks/zap_core.go | 61 +++++++
.../frameworks/{zap_adapt.go => zap_root.go} | 28 ++-
tools/go-agent/instrument/logger/instrument.go | 92 +++++++---
tools/go-agent/instrument/plugins/rewrite/var.go | 2 +-
45 files changed, 1073 insertions(+), 180 deletions(-)
diff --git a/.github/workflows/plugin-tests.yaml
b/.github/workflows/plugin-tests.yaml
index 21b57c3..714d805 100644
--- a/.github/workflows/plugin-tests.yaml
+++ b/.github/workflows/plugin-tests.yaml
@@ -79,6 +79,8 @@ jobs:
- microv4
- mongo
- mysql
+ - zap
+ - logrus
- plugin_exclusion
- runtime_metrics
steps:
diff --git a/CHANGES.md b/CHANGES.md
index e02b0fc..4dd0f75 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,12 +8,17 @@ Release Notes.
* Enhance the plugin rewrite ability to support `switch` and `if/else` in the
plugin codes.
* Support inject the skywalking-go into project through agent.
* Support add configuration for plugin.
+* Support metrics report API for plugin.
+* Support report Golang runtime metrics.
+* Support log reporter.
#### Plugins
* Support [go-redis](https://github.com/redis/go-redis) v9 redis client
framework.
* Support collecting [Native HTTP](https://pkg.go.dev/net/http) URI parameter
on server side.
* Support [Mongo](https://github.com/mongodb/mongo-go-driver) database client
framework.
* Support [Native SQL](https://pkg.go.dev/net/http) database client framework
with [MySQL Driver](github.com/go-sql-driver/mysql).
+* Support [Logrus](https://github.com/sirupsen/logrus) log report to the
backend.
+* Support [Zap](https://github.com/uber-go/zap) log report to the backend.
#### Documentation
diff --git a/go.work b/go.work
index 0e4fc6e..a2d1d46 100644
--- a/go.work
+++ b/go.work
@@ -33,6 +33,8 @@ use (
./test/plugins/scenarios/microv4
./test/plugins/scenarios/mongo
./test/plugins/scenarios/mysql
+ ./test/plugins/scenarios/logrus
+ ./test/plugins/scenarios/zap
./test/plugins/scenarios/plugin_exclusion
./test/plugins/scenarios/runtime_metrics
diff --git a/plugins/core/logreport.go b/plugins/core/logreport.go
new file mode 100644
index 0000000..361b462
--- /dev/null
+++ b/plugins/core/logreport.go
@@ -0,0 +1,87 @@
+// 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 core
+
+import (
+ "time"
+
+ commonv3 "skywalking.apache.org/repo/goapi/collect/common/v3"
+ logv3 "skywalking.apache.org/repo/goapi/collect/logging/v3"
+)
+
+func (t *Tracer) LogReporter() interface{} {
+ return t
+}
+
+type logTracingContext interface {
+ GetServiceName() string
+ GetInstanceName() string
+ GetTraceID() string
+ GetTraceSegmentID() string
+ GetSpanID() int32
+ GetEndPointName() string
+}
+
+func (t *Tracer) ReportLog(ctx, timeObj interface{}, level, msg string, labels
map[string]string) {
+ tracingContext, ok := ctx.(logTracingContext)
+ if !ok || tracingContext == nil {
+ return
+ }
+ entity := t.ServiceEntity
+ if entity == nil {
+ return
+ }
+ timeData := timeObj.(time.Time)
+
+ tags := &logv3.LogTags{
+ Data: []*commonv3.KeyStringValuePair{
+ {
+ Key: "LEVEL",
+ Value: level,
+ },
+ },
+ }
+ for k, v := range labels {
+ tags.Data = append(tags.Data, &commonv3.KeyStringValuePair{
+ Key: k,
+ Value: v,
+ })
+ }
+
+ logData := &logv3.LogData{
+ Timestamp: Millisecond(timeData),
+ Service: tracingContext.GetServiceName(),
+ ServiceInstance: tracingContext.GetInstanceName(),
+ Endpoint: tracingContext.GetEndPointName(),
+ Body: &logv3.LogDataBody{
+ Type: "TEXT",
+ Content: &logv3.LogDataBody_Text{
+ Text: &logv3.TextLog{Text: msg},
+ },
+ },
+ TraceContext: &logv3.TraceContext{
+ TraceId: tracingContext.GetTraceID(),
+ TraceSegmentId: tracingContext.GetTraceSegmentID(),
+ SpanId: tracingContext.GetSpanID(),
+ },
+ Tags: tags,
+ Layer: "GENERAL",
+ }
+
+ t.Reporter.SendLog(logData)
+}
diff --git a/plugins/core/operator/common.go b/plugins/core/operator/common.go
index 55260bb..dbe7684 100644
--- a/plugins/core/operator/common.go
+++ b/plugins/core/operator/common.go
@@ -23,12 +23,13 @@ var MetricsAppender = func(interface{}) {}
var MetricsCollectAppender = func(func()) {}
type Operator interface {
- Tracing() interface{} // to TracingOperator
- Logger() interface{} // to LogOperator
- 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
- Metrics() interface{} // to MetricsOperator
+ Tracing() interface{} // to TracingOperator
+ Logger() interface{} // to LogOperator
+ 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
+ Metrics() interface{} // to MetricsOperator
+ LogReporter() interface{} // to LogReporter
}
type Entity interface {
diff --git a/plugins/core/operator/logger.go b/plugins/core/operator/logger.go
index 53358e8..b7b0aef 100644
--- a/plugins/core/operator/logger.go
+++ b/plugins/core/operator/logger.go
@@ -27,3 +27,7 @@ type LogOperator interface {
Error(args ...interface{})
Errorf(format string, args ...interface{})
}
+
+type LogReporter interface {
+ ReportLog(ctx, time interface{}, level, msg string, labels
map[string]string)
+}
diff --git a/plugins/core/reporter/api.go b/plugins/core/reporter/api.go
index ce3b30a..02f9585 100644
--- a/plugins/core/reporter/api.go
+++ b/plugins/core/reporter/api.go
@@ -20,6 +20,7 @@ package reporter
import (
commonv3 "skywalking.apache.org/repo/goapi/collect/common/v3"
agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
+ logv3 "skywalking.apache.org/repo/goapi/collect/logging/v3"
)
// Tag are supported by sky-walking engine.
@@ -108,6 +109,7 @@ type Reporter interface {
Boot(entity *Entity, cdsWatchers []AgentConfigChangeWatcher)
SendTracing(spans []ReportedSpan)
SendMetrics(metrics []ReportedMeter)
+ SendLog(log *logv3.LogData)
ConnectionStatus() ConnectionStatus
Close()
}
diff --git a/plugins/core/reporter/grpc/grpc.go
b/plugins/core/reporter/grpc/grpc.go
index 8013f67..cc30c76 100644
--- a/plugins/core/reporter/grpc/grpc.go
+++ b/plugins/core/reporter/grpc/grpc.go
@@ -30,6 +30,7 @@ import (
configuration
"skywalking.apache.org/repo/goapi/collect/agent/configuration/v3"
agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
+ logv3 "skywalking.apache.org/repo/goapi/collect/logging/v3"
managementv3 "skywalking.apache.org/repo/goapi/collect/management/v3"
"github.com/apache/skywalking-go/plugins/core/operator"
@@ -48,6 +49,7 @@ func NewGRPCReporter(logger operator.LogOperator, serverAddr
string, opts ...Rep
logger: logger,
tracingSendCh: make(chan *agentv3.SegmentObject,
maxSendQueueSize),
metricsSendCh: make(chan []*agentv3.MeterData,
maxSendQueueSize),
+ logSendCh: make(chan *logv3.LogData, maxSendQueueSize),
checkInterval: defaultCheckInterval,
cdsInterval: defaultCDSInterval, // cds default on
connectionStatus: reporter.ConnectionStatusConnected,
@@ -71,6 +73,7 @@ func NewGRPCReporter(logger operator.LogOperator, serverAddr
string, opts ...Rep
r.conn = conn
r.traceClient = agentv3.NewTraceSegmentReportServiceClient(r.conn)
r.metricsClient = agentv3.NewMeterReportServiceClient(r.conn)
+ r.logClient = logv3.NewLogReportServiceClient(r.conn)
r.managementClient = managementv3.NewManagementServiceClient(r.conn)
if r.cdsInterval > 0 {
r.cdsClient =
configuration.NewConfigurationDiscoveryServiceClient(r.conn)
@@ -84,9 +87,11 @@ type gRPCReporter struct {
logger operator.LogOperator
tracingSendCh chan *agentv3.SegmentObject
metricsSendCh chan []*agentv3.MeterData
+ logSendCh chan *logv3.LogData
conn *grpc.ClientConn
traceClient agentv3.TraceSegmentReportServiceClient
metricsClient agentv3.MeterReportServiceClient
+ logClient logv3.LogReportServiceClient
managementClient managementv3.ManagementServiceClient
checkInterval time.Duration
cdsInterval time.Duration
@@ -236,6 +241,19 @@ func (r *gRPCReporter) SendMetrics(metrics
[]reporter.ReportedMeter) {
}
}
+func (r *gRPCReporter) SendLog(log *logv3.LogData) {
+ defer func() {
+ if err := recover(); err != nil {
+ r.logger.Errorf("reporter log err %v", err)
+ }
+ }()
+ select {
+ case r.logSendCh <- log:
+ default:
+ r.logger.Errorf("reach max logger send buffer")
+ }
+}
+
func (r *gRPCReporter) convertLabels(labels map[string]string)
[]*agentv3.Label {
if len(labels) == 0 {
return nil
@@ -320,6 +338,27 @@ func (r *gRPCReporter) initSendPipeline() {
break
}
}()
+ go func() {
+ StreamLoop:
+ for {
+ stream, err :=
r.logClient.Collect(metadata.NewOutgoingContext(context.Background(), r.md))
+ if err != nil {
+ r.logger.Errorf("open stream error %v", err)
+ time.Sleep(5 * time.Second)
+ continue StreamLoop
+ }
+ for s := range r.logSendCh {
+ err = stream.Send(s)
+ if err != nil {
+ r.logger.Errorf("send log error %v",
err)
+ r.closeLogStream(stream)
+ continue StreamLoop
+ }
+ }
+ r.closeLogStream(stream)
+ break
+ }
+ }()
}
func (r *gRPCReporter) initCDS(cdsWatchers
[]reporter.AgentConfigChangeWatcher) {
@@ -372,6 +411,13 @@ func (r *gRPCReporter) closeMetricsStream(stream
agentv3.MeterReportService_Coll
}
}
+func (r *gRPCReporter) closeLogStream(stream
logv3.LogReportService_CollectClient) {
+ _, err := stream.CloseAndRecv()
+ if err != nil && err != io.EOF {
+ r.logger.Errorf("send closing error %v", err)
+ }
+}
+
func (r *gRPCReporter) reportInstanceProperties() (err error) {
_, err =
r.managementClient.ReportInstanceProperties(metadata.NewOutgoingContext(context.Background(),
r.md), &managementv3.InstanceProperties{
Service: r.entity.ServiceName,
diff --git a/plugins/core/span_default.go b/plugins/core/span_default.go
index 9f38401..0e53a17 100644
--- a/plugins/core/span_default.go
+++ b/plugins/core/span_default.go
@@ -191,3 +191,14 @@ func (ds *DefaultSpan) AsyncFinish() {
}
ds.AsyncModeFinished = true
}
+
+func (ds *DefaultSpan) GetEndPointName() string {
+ if ds.SpanType == SpanTypeEntry {
+ return ds.OperationName
+ }
+ return ""
+}
+
+func (ds *DefaultSpan) GetParentSpan() interface{} {
+ return ds.Parent
+}
diff --git a/plugins/core/span_noop.go b/plugins/core/span_noop.go
index 4c40fbd..85cff00 100644
--- a/plugins/core/span_noop.go
+++ b/plugins/core/span_noop.go
@@ -99,3 +99,11 @@ func (n *NoopSpan) PrepareAsync() {
func (n *NoopSpan) AsyncFinish() {
}
+
+func (n *NoopSpan) GetEndPointName() string {
+ return ""
+}
+
+func (n *NoopSpan) GetParentSpan() interface{} {
+ return nil
+}
diff --git a/plugins/core/test_base.go b/plugins/core/test_base.go
index 148aaf1..5fa2ae3 100644
--- a/plugins/core/test_base.go
+++ b/plugins/core/test_base.go
@@ -22,6 +22,8 @@ import (
"github.com/apache/skywalking-go/plugins/core/operator"
"github.com/apache/skywalking-go/plugins/core/reporter"
+
+ logv3 "skywalking.apache.org/repo/goapi/collect/logging/v3"
)
var tlsData interface{}
@@ -66,6 +68,7 @@ func GetReportedSpans() []reporter.ReportedSpan {
type StoreReporter struct {
Spans []reporter.ReportedSpan
Metrics []reporter.ReportedMeter
+ Logs []*logv3.LogData
}
func NewStoreReporter() *StoreReporter {
@@ -83,6 +86,10 @@ func (r *StoreReporter) SendMetrics(metrics
[]reporter.ReportedMeter) {
r.Metrics = append(r.Metrics, metrics...)
}
+func (r *StoreReporter) SendLog(log *logv3.LogData) {
+ r.Logs = append(r.Logs, log)
+}
+
func (r *StoreReporter) ConnectionStatus() reporter.ConnectionStatus {
return ReportConnectionStatus
}
diff --git a/plugins/core/tracer.go b/plugins/core/tracer.go
index df0ef68..eedd3b2 100644
--- a/plugins/core/tracer.go
+++ b/plugins/core/tracer.go
@@ -26,6 +26,8 @@ import (
"github.com/apache/skywalking-go/plugins/core/operator"
"github.com/apache/skywalking-go/plugins/core/reporter"
+
+ logv3 "skywalking.apache.org/repo/goapi/collect/logging/v3"
)
// nolint
@@ -135,6 +137,10 @@ func (e *emptyReporter) SendTracing(spans
[]reporter.ReportedSpan) {
func (e *emptyReporter) SendMetrics(metrics []reporter.ReportedMeter) {
}
+// nolint
+func (e *emptyReporter) SendLog(log *logv3.LogData) {
+}
+
func (e *emptyReporter) ConnectionStatus() reporter.ConnectionStatus {
return reporter.ConnectionStatusDisconnect
}
diff --git a/plugins/go-redisv9/go.mod b/plugins/go-redisv9/go.mod
index 6260bf4..51b7dd1 100644
--- a/plugins/go-redisv9/go.mod
+++ b/plugins/go-redisv9/go.mod
@@ -2,12 +2,9 @@ module github.com/apache/skywalking-go/plugins/go-redisv9
go 1.18
-require (
- github.com/redis/go-redis/v9 v9.0.5
-)
+require github.com/redis/go-redis/v9 v9.0.5
require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/dave/dst v0.27.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f //
indirect
)
diff --git a/plugins/go-redisv9/go.sum b/plugins/go-redisv9/go.sum
index b269a6f..51a6329 100644
--- a/plugins/go-redisv9/go.sum
+++ b/plugins/go-redisv9/go.sum
@@ -1,23 +1,8 @@
-github.com/apache/skywalking-go/plugins/core
v0.0.0-20230531133153-0c54f7fe6e62
h1:geTGEa3GDXLbgAjJnzHliEVsL9rShyJMPI4oXdTuS+4=
-github.com/apache/skywalking-go/plugins/core
v0.0.0-20230531133153-0c54f7fe6e62/go.mod
h1:P0tAFNAYJUNsiTlFQgxmCcRcu+7Y0MP8GBZfSI449CM=
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
-github.com/bsm/ginkgo/v2 v2.7.0/go.mod
h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
-github.com/bsm/gomega v1.26.0/go.mod
h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cespare/xxhash/v2 v2.2.0
h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod
h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/dave/dst v0.27.2 h1:4Y5VFTkhGLC1oddtNwuxxe36pnyLxMFXT51FOzH8Ekc=
-github.com/dave/dst v0.27.2/go.mod
h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc=
-github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod
h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5
h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
-github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod
h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
github.com/redis/go-redis/v9 v9.0.5
h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
github.com/redis/go-redis/v9 v9.0.5/go.mod
h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
-github.com/stretchr/testify v1.8.2
h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
-golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
-golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/plugins/gorm/go.mod b/plugins/gorm/go.mod
index 504358b..ee80d26 100644
--- a/plugins/gorm/go.mod
+++ b/plugins/gorm/go.mod
@@ -3,7 +3,7 @@ module github.com/apache/skywalking-go/plugins/gorm
go 1.18
require (
- github.com/go-sql-driver/mysql v1.7.0
+ github.com/go-sql-driver/mysql v1.7.1
github.com/stretchr/testify v1.8.2
gorm.io/driver/mysql v1.5.1
gorm.io/gorm v1.25.1
diff --git a/plugins/gorm/go.sum b/plugins/gorm/go.sum
index 0fbbbcf..7a90168 100644
--- a/plugins/gorm/go.sum
+++ b/plugins/gorm/go.sum
@@ -1,5 +1,5 @@
github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/go-sql-driver/mysql v1.7.0
h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
+github.com/go-sql-driver/mysql v1.7.1
h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/jinzhu/inflection v1.0.0
h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod
h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
diff --git a/plugins/runtimemetrics/instrument.go
b/plugins/runtimemetrics/instrument.go
index cadf05a..082cada 100644
--- a/plugins/runtimemetrics/instrument.go
+++ b/plugins/runtimemetrics/instrument.go
@@ -35,7 +35,7 @@ func NewInstrument() *Instrument {
}
func (r *Instrument) Name() string {
- return "runtime-metrics"
+ return "runtimemetrics"
}
func (r *Instrument) BasePackage() string {
diff --git a/test/plugins/scenarios/logrus/bin/startup.sh
b/test/plugins/scenarios/logrus/bin/startup.sh
new file mode 100755
index 0000000..14e3ffa
--- /dev/null
+++ b/test/plugins/scenarios/logrus/bin/startup.sh
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+home="$(cd "$(dirname $0)"; pwd)"
+go build ${GO_BUILD_OPTS} -o logrus
+
+export SW_AGENT_LOG_REPORTER_LABEL_KEYS=module
+
+./logrus
\ No newline at end of file
diff --git a/test/plugins/scenarios/logrus/config/excepted.yml
b/test/plugins/scenarios/logrus/config/excepted.yml
new file mode 100644
index 0000000..983c4aa
--- /dev/null
+++ b/test/plugins/scenarios/logrus/config/excepted.yml
@@ -0,0 +1,67 @@
+# 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: []
+meterItems: []
+logItems:
+ - serviceName: logrus
+ logSize: ge 3
+ logs:
+ - timestamp: nq 0
+ endpoint: ''
+ body:
+ type: TEXT
+ 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:
+ - { key: LEVEL, value: error }
+ layer: GENERAL
+ - timestamp: nq 0
+ endpoint: GET:/provider
+ body:
+ type: TEXT
+ content:
+ text: providerHandler
+ traceContext:
+ traceId: not null
+ traceSegmentId: not null
+ spanId: 0
+ tags:
+ data:
+ - key: LEVEL
+ value: info
+ - key: module
+ value: test-service
+ layer: GENERAL
+ - timestamp: nq 0
+ endpoint: GET:/consumer
+ body:
+ type: TEXT
+ content:
+ text: consumerHandler
+ traceContext:
+ traceId: not null
+ traceSegmentId: not null
+ spanId: 0
+ tags:
+ data:
+ - key: LEVEL
+ value: info
+ - key: module
+ value: test-service
+ layer: GENERAL
diff --git a/test/plugins/scenarios/logrus/go.mod
b/test/plugins/scenarios/logrus/go.mod
new file mode 100644
index 0000000..82a3a0f
--- /dev/null
+++ b/test/plugins/scenarios/logrus/go.mod
@@ -0,0 +1,8 @@
+module test/plugins/scenarios/logrus
+
+go 1.18
+
+require (
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
+)
diff --git a/test/plugins/scenarios/logrus/go.sum
b/test/plugins/scenarios/logrus/go.sum
new file mode 100644
index 0000000..2cbdecd
--- /dev/null
+++ b/test/plugins/scenarios/logrus/go.sum
@@ -0,0 +1,11 @@
+github.com/davecgh/go-spew v1.1.0/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/sirupsen/logrus v1.9.3
h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod
h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/stretchr/objx v0.1.0/go.mod
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/test/plugins/scenarios/logrus/main.go
b/test/plugins/scenarios/logrus/main.go
new file mode 100644
index 0000000..fd43394
--- /dev/null
+++ b/test/plugins/scenarios/logrus/main.go
@@ -0,0 +1,67 @@
+// 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 (
+ "io"
+ "net/http"
+
+ "github.com/sirupsen/logrus"
+
+ _ "github.com/apache/skywalking-go"
+)
+
+var (
+ log = logrus.WithField("module", "test-service")
+)
+
+func providerHandler(w http.ResponseWriter, r *http.Request) {
+ log.Infof("providerHandler")
+ _, _ = w.Write([]byte("success"))
+}
+
+func consumerHandler(w http.ResponseWriter, r *http.Request) {
+ 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
+ }
+ log.Infof("consumerHandler")
+ _, _ = w.Write(body)
+}
+
+func main() {
+ logrus.SetFormatter(&logrus.JSONFormatter{})
+
+ http.HandleFunc("/provider", providerHandler)
+ http.HandleFunc("/consumer", consumerHandler)
+
+ http.HandleFunc("/health", func(writer http.ResponseWriter, request
*http.Request) {
+ writer.WriteHeader(http.StatusOK)
+ })
+
+ _ = http.ListenAndServe(":8080", nil)
+}
diff --git a/test/plugins/scenarios/logrus/plugin.yml
b/test/plugins/scenarios/logrus/plugin.yml
new file mode 100644
index 0000000..eb2cd80
--- /dev/null
+++ b/test/plugins/scenarios/logrus/plugin.yml
@@ -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.
+
+entry-service: http://${HTTP_HOST}:${HTTP_PORT}/consumer
+health-checker: http://${HTTP_HOST}:${HTTP_PORT}/health
+start-script: ./bin/startup.sh
+framework: github.com/sirupsen/logrus
+export-port: 8080
+support-version:
+ - go: 1.18
+ framework:
+ - v1.8.2
+ - v1.8.3
+ - v1.9.0
+ - v1.9.1
+ - v1.9.2
+ - v1.9.3
diff --git a/test/plugins/scenarios/zap/bin/startup.sh
b/test/plugins/scenarios/zap/bin/startup.sh
new file mode 100755
index 0000000..3ae8704
--- /dev/null
+++ b/test/plugins/scenarios/zap/bin/startup.sh
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+home="$(cd "$(dirname $0)"; pwd)"
+go build ${GO_BUILD_OPTS} -o zap
+
+export SW_AGENT_LOG_REPORTER_LABEL_KEYS=module
+
+./zap
\ No newline at end of file
diff --git a/test/plugins/scenarios/zap/config/excepted.yml
b/test/plugins/scenarios/zap/config/excepted.yml
new file mode 100644
index 0000000..0b927f9
--- /dev/null
+++ b/test/plugins/scenarios/zap/config/excepted.yml
@@ -0,0 +1,67 @@
+# 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: []
+meterItems: []
+logItems:
+ - serviceName: zap
+ logSize: ge 3
+ logs:
+ - timestamp: nq 0
+ endpoint: ''
+ body:
+ type: TEXT
+ 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:
+ - { key: LEVEL, value: error }
+ layer: GENERAL
+ - timestamp: nq 0
+ endpoint: GET:/provider
+ body:
+ type: TEXT
+ content:
+ text: providerHandler
+ traceContext:
+ traceId: not null
+ traceSegmentId: not null
+ spanId: 0
+ tags:
+ data:
+ - key: LEVEL
+ value: info
+ - key: module
+ value: test-service-provider
+ layer: GENERAL
+ - timestamp: nq 0
+ endpoint: GET:/consumer
+ body:
+ type: TEXT
+ content:
+ text: consumerHandler
+ traceContext:
+ traceId: not null
+ traceSegmentId: not null
+ spanId: 0
+ tags:
+ data:
+ - key: LEVEL
+ value: info
+ - key: module
+ value: test-service-consumer
+ layer: GENERAL
diff --git a/test/plugins/scenarios/zap/go.mod
b/test/plugins/scenarios/zap/go.mod
new file mode 100644
index 0000000..02bec57
--- /dev/null
+++ b/test/plugins/scenarios/zap/go.mod
@@ -0,0 +1,3 @@
+module test/plugins/scenarios/zap
+
+go 1.18
diff --git a/test/plugins/scenarios/zap/go.sum
b/test/plugins/scenarios/zap/go.sum
new file mode 100644
index 0000000..e69de29
diff --git a/test/plugins/scenarios/zap/main.go
b/test/plugins/scenarios/zap/main.go
new file mode 100644
index 0000000..9ed157f
--- /dev/null
+++ b/test/plugins/scenarios/zap/main.go
@@ -0,0 +1,66 @@
+// 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 (
+ "io"
+ "net/http"
+
+ "go.uber.org/zap"
+
+ _ "github.com/apache/skywalking-go"
+)
+
+var (
+ logger, _ = zap.NewProduction()
+ log = logger.Sugar()
+)
+
+func providerHandler(w http.ResponseWriter, r *http.Request) {
+ log.With("module", "test-service-provider").Info("providerHandler")
+ _, _ = w.Write([]byte("success"))
+}
+
+func consumerHandler(w http.ResponseWriter, r *http.Request) {
+ resp, err := http.Get("http://localhost:8080/provider?test=1")
+ if err != nil {
+ log.Warnf("request provider, error: %v", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ defer resp.Body.Close()
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ log.Warn(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ log.With("module", "test-service-consumer").Info("consumerHandler")
+ _, _ = w.Write(body)
+}
+
+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(":8080", nil)
+}
diff --git a/test/plugins/scenarios/zap/plugin.yml
b/test/plugins/scenarios/zap/plugin.yml
new file mode 100644
index 0000000..c066873
--- /dev/null
+++ b/test/plugins/scenarios/zap/plugin.yml
@@ -0,0 +1,34 @@
+# 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.uber.org/zap
+export-port: 8080
+support-version:
+ - go: 1.18
+ framework:
+ - v1.17.0
+ - v1.18.0
+ - v1.18.1
+ - v1.19.0
+ - v1.19.1
+ - v1.20.0
+ - v1.21.0
+ - v1.22.0
+ - v1.23.0
+ - v1.24.0
diff --git a/tools/go-agent/config/agent.default.yaml
b/tools/go-agent/config/agent.default.yaml
index 02fa6ba..2cafd61 100644
--- a/tools/go-agent/config/agent.default.yaml
+++ b/tools/go-agent/config/agent.default.yaml
@@ -51,6 +51,11 @@ log:
enable: ${SW_AGENT_LOG_TRACING_ENABLE:true}
# If tracing information is enabled, the tracing information would be
stored in the current Key in each log.
key: ${SW_AGENT_LOG_TRACING_KEY:SW_CTX}
+ reporter:
+ # Whether to upload logs to the backend.
+ enable: ${SW_AGENT_LOG_REPORTER_ENABLE:true}
+ # The fields name list that needs to added to the label of the
log.(multiple split by ",")
+ label_keys: ${SW_AGENT_LOG_REPORTER_LABEL_KEYS:}
plugin:
# List the names of excluded plugins, multiple plugin names should be
splitted by ","
diff --git a/tools/go-agent/config/loader.go b/tools/go-agent/config/loader.go
index 8d9324d..28e2897 100644
--- a/tools/go-agent/config/loader.go
+++ b/tools/go-agent/config/loader.go
@@ -56,8 +56,9 @@ type Reporter struct {
}
type Log struct {
- Type StringValue `yaml:"type"`
- Tracing LogTracing `yaml:"tracing"`
+ Type StringValue `yaml:"type"`
+ Tracing LogTracing `yaml:"tracing"`
+ Reporter LogReporter `yaml:"reporter"`
}
type LogTracing struct {
@@ -65,6 +66,11 @@ type LogTracing struct {
Key StringValue `yaml:"key"`
}
+type LogReporter struct {
+ Enabled StringValue `yaml:"enable"`
+ LabelKeys StringValue `yaml:"label_keys"`
+}
+
type Meter struct {
CollectInterval StringValue `yaml:"collect_interval"`
}
@@ -181,6 +187,26 @@ func (s *StringValue) ToGoStringValue() string {
}()`, s.EnvKey, s.Default, s.EnvKey, s.Default), "\n", ";")
}
+func (s *StringValue) ToGoStringListValue() string {
+ return strings.ReplaceAll(fmt.Sprintf(`func() []string {
+ splitResult := func(s string) []string {
+ t := strings.Split(s, ",")
+ if len(t) == 1 && t[0] == "" { return nil }
+ res := make([]string, 0, 0)
+ for _, v := range t {
+ if v != "" {
+ res = append(res, v)
+ }
+ }
+ return res
+ }
+ if "%s" == "" { return splitResult("%s") }
+ tmpValue := os.Getenv("%s")
+ if tmpValue == "" { return splitResult("%s") }
+ return splitResult(tmpValue)
+}()`, s.EnvKey, s.Default, s.EnvKey, s.Default), "\n", ";")
+}
+
func (s *StringValue) ToGoStringFunction() string {
return fmt.Sprintf("func() string { return %s }", s.ToGoStringValue())
}
diff --git a/tools/go-agent/instrument/consts/operator.go
b/tools/go-agent/instrument/consts/operator.go
index da8ff5c..a9b726b 100644
--- a/tools/go-agent/instrument/consts/operator.go
+++ b/tools/go-agent/instrument/consts/operator.go
@@ -27,16 +27,16 @@ const (
GlobalTracerSnapshotInterface = "skywalkingGoroutineSnapshotCreator"
- GlobalTracerSetMethodName =
"_skywalking_set_global_operator"
- GlobalTracerGetMethodName =
"_skywalking_get_global_operator"
- GlobalLoggerSetMethodName = "_skywalking_set_global_logger"
- GlobalLoggerGetMethodName = "_skywalking_get_global_logger"
- GlobalTracerInitAppendNotifyMethodName =
"_skywalking_global_init_append_notify"
- GlobalTracerInitGetNotifyMethodName =
"_skywalking_global_init_get_notify"
+ GlobalTracerSetMethodName =
"skywalking_set_global_operator"
+ GlobalTracerGetMethodName =
"skywalking_get_global_operator"
+ GlobalLoggerSetMethodName = "skywalking_set_global_logger"
+ GlobalLoggerGetMethodName = "skywalking_get_global_logger"
+ GlobalTracerInitAppendNotifyMethodName =
"skywalking_global_init_append_notify"
+ GlobalTracerInitGetNotifyMethodName =
"skywalking_global_init_get_notify"
- MetricsRegisterAppendMethodName = "_skywalking_metrics_register_append"
- MetricsObtainMethodName = "_skywalking_metrics_obtain"
- MetricsHookAppendMethodName = "_skywalking_metrics_hook_append"
+ MetricsRegisterAppendMethodName = "skywalking_metrics_register_append"
+ MetricsObtainMethodName = "skywalking_metrics_obtain"
+ MetricsHookAppendMethodName = "skywalking_metrics_hook_append"
- CurrentGoroutineIDGetMethodName = "_skywalking_get_goid"
+ CurrentGoroutineIDGetMethodName = "skywalking_get_goid"
)
diff --git a/tools/go-agent/instrument/consts/tls.go
b/tools/go-agent/instrument/consts/tls.go
index 7395ffa..b28e4ac 100644
--- a/tools/go-agent/instrument/consts/tls.go
+++ b/tools/go-agent/instrument/consts/tls.go
@@ -19,6 +19,6 @@ package consts
const (
TLSFieldName = "skywalking_tls"
- TLSGetMethodName = "_skywalking_get_gls"
- TLSSetMethodName = "_skywalking_set_gls"
+ TLSGetMethodName = "skywalking_get_gls"
+ TLSSetMethodName = "skywalking_set_gls"
)
diff --git a/tools/go-agent/instrument/logger/context.go
b/tools/go-agent/instrument/logger/context.go
index 54e73f5..25defd3 100644
--- a/tools/go-agent/instrument/logger/context.go
+++ b/tools/go-agent/instrument/logger/context.go
@@ -28,6 +28,7 @@ type Operator interface {
Tracing() interface{}
ChangeLogger(logger interface{})
Entity() interface{}
+ LogReporter() interface{}
}
type TracingOperator interface {
@@ -38,6 +39,8 @@ type TracingSpan interface {
GetTraceID() string
GetSegmentID() string
GetSpanID() int32
+ GetEndPointName() string
+ GetParentSpan() interface{}
}
type Entity interface {
@@ -60,24 +63,60 @@ func (span *NoopSpan) GetSpanID() int32 {
return -1
}
+func (span *NoopSpan) GetParentSpan() interface{} {
+ return nil
+}
+
+func (span *NoopSpan) GetEndPointName() string {
+ return ""
+}
+
type SkyWalkingLogContext struct {
ServiceName string
InstanceName string
TraceID string
+ EndPoint string
TraceSegmentID string
SpanID int32
}
+func (s *SkyWalkingLogContext) GetServiceName() string {
+ return s.ServiceName
+}
+
+func (s *SkyWalkingLogContext) GetInstanceName() string {
+ return s.InstanceName
+}
+
+func (s *SkyWalkingLogContext) GetTraceID() string {
+ return s.TraceID
+}
+
+func (s *SkyWalkingLogContext) GetTraceSegmentID() string {
+ return s.TraceSegmentID
+}
+
+func (s *SkyWalkingLogContext) GetSpanID() int32 {
+ return s.SpanID
+}
+
+func (s *SkyWalkingLogContext) GetEndPointName() string {
+ return s.EndPoint
+}
+
var noopContext = &NoopSpan{}
-func GetLogContext() *SkyWalkingLogContext {
+func GetLogContext(withEndpoint bool) *SkyWalkingLogContext {
operator := GetOperator()
var activeSpan TracingSpan = noopContext
- var serviceName, instanceName string
+ var serviceName, instanceName, endpoint string
if operator != nil {
tracingOperator := operator.Tracing().(TracingOperator)
- if s, ok := tracingOperator.ActiveSpan().(TracingSpan); ok {
+ if s, ok := tracingOperator.ActiveSpan().(TracingSpan); ok && s
!= nil {
activeSpan = s
+ if withEndpoint {
+ endpoint = findEndpointNameBySpan(s)
+ }
}
entity := operator.Entity()
if entity != nil {
@@ -92,14 +131,31 @@ func GetLogContext() *SkyWalkingLogContext {
TraceID: activeSpan.GetTraceID(),
TraceSegmentID: activeSpan.GetSegmentID(),
SpanID: activeSpan.GetSpanID(),
+ EndPoint: endpoint,
+ }
+}
+
+func findEndpointNameBySpan(s TracingSpan) string {
+ tmp := s
+ for tmp != nil {
+ if name := tmp.GetEndPointName(); name != "" {
+ return name
+ }
+ parent := tmp.GetParentSpan()
+ if parentTmp, ok := parent.(TracingSpan); ok && parentTmp !=
nil {
+ tmp = parentTmp
+ } else {
+ tmp = nil
+ }
}
+ return ""
}
func GetLogContextString() string {
- return GetLogContext().String()
+ return GetLogContext(false).String()
}
-func (context *SkyWalkingLogContext) String() string {
- return fmt.Sprintf("[%s,%s,%s,%s,%d]", context.ServiceName,
context.InstanceName,
- context.TraceID, context.TraceSegmentID, context.SpanID)
+func (s *SkyWalkingLogContext) String() string {
+ return fmt.Sprintf("[%s,%s,%s,%s,%d]", s.ServiceName, s.InstanceName,
+ s.TraceID, s.TraceSegmentID, s.SpanID)
}
diff --git a/tools/go-agent/instrument/logger/context_test.go
b/tools/go-agent/instrument/logger/context_test.go
index 4642209..6469cd4 100644
--- a/tools/go-agent/instrument/logger/context_test.go
+++ b/tools/go-agent/instrument/logger/context_test.go
@@ -32,19 +32,32 @@ func init() {
}
}
+type ExtractorWrapper struct {
+ F func(headerKey string) (string, error)
+}
+
+func (e *ExtractorWrapper) Fun() func(headerKey string) (string, error) {
+ return e.F
+}
+
func TestGetLogContext(t *testing.T) {
serviceName := "test-service"
serviceInstanceName := "test-instance"
core.Tracing.ServiceEntity = &reporter.Entity{ServiceName: serviceName,
ServiceInstanceName: serviceInstanceName}
- s, err := core.Tracing.CreateLocalSpan("/test")
+ s, err := core.Tracing.CreateEntrySpan("/test", &ExtractorWrapper{
+ F: func(headerKey string) (string, error) {
+ return "", nil
+ },
+ })
assert.Nil(t, err, "err should be nil")
assert.NotNil(t, s, "span cannot be nil")
- context := GetLogContext()
+ context := GetLogContext(true)
assert.NotNil(t, context, "context cannot be nil")
rootSpan, ok := s.(*core.RootSegmentSpan)
assert.True(t, ok, "span should be root span")
assert.Equal(t, serviceName, context.ServiceName, "service name should
be equal")
assert.Equal(t, serviceInstanceName, serviceInstanceName, "service
instance name should be equal")
+ assert.Equal(t, "/test", context.GetEndPointName(), "endpoint name
should be equal")
assert.Equal(t, rootSpan.Context().GetTraceID(), context.TraceID,
"trace id should be equal")
assert.Equal(t, rootSpan.Context().GetSegmentID(),
context.TraceSegmentID, "trace segment id should be equal")
assert.Equal(t, rootSpan.Context().GetSpanID(), context.SpanID, "span
id should be equal")
diff --git a/tools/go-agent/instrument/logger/frameworks/api.go
b/tools/go-agent/instrument/logger/frameworks/api.go
index 9f44234..c6c9a65 100644
--- a/tools/go-agent/instrument/logger/frameworks/api.go
+++ b/tools/go-agent/instrument/logger/frameworks/api.go
@@ -19,6 +19,8 @@ package frameworks
import (
"embed"
+ "fmt"
+ "time"
"github.com/apache/skywalking-go/plugins/core/operator"
"github.com/apache/skywalking-go/tools/go-agent/instrument/plugins/rewrite"
@@ -37,14 +39,21 @@ var ChangeLogger = func(i operator.LogOperator) {
}
// LogTracingContextEnable check log the tracing context enable
-var LogTracingContextEnable = func() bool {
- return false
-}
+var LogTracingContextEnable = false
+
+// LogReporterEnable check log the reporter enable
+var LogReporterEnable = false
+
+// LogReporterLabelKeys get the reporter customized label keys
+var LogReporterLabelKeys []string
// LogTracingContextKey get the tracing context key
// nolint
-var LogTracingContextKey = func() string {
- return "SW_CTX"
+var LogTracingContextKey = "SW_CTX"
+
+// GetLogContext get the tracing context
+var GetLogContext = func(withEndpoint bool) fmt.Stringer {
+ return nil
}
// GetLogContextString get the log context string
@@ -52,15 +61,23 @@ func GetLogContextString() string {
return ""
}
+// ReportLog report the log to backend
+var ReportLog = func(ctx interface{}, time time.Time, level, msg string,
labels map[string]string) {
+}
+
type PackageConfiguration struct {
// needs to generate the operator helpers
NeedsHelpers bool
+ // needs to generate the operator variables
+ NeedsVariables bool
+ // needs the change logger method
+ NeedsChangeLoggerFunc bool
}
type LogFramework interface {
// Name of the framework
Name() string
- // PackagePaths of the framework, define which package needs to be
instrument
+ // PackagePaths of the framework, define which package needs to be
instrumented
PackagePaths() map[string]*PackageConfiguration
// AutomaticBindFunctions if the filtered method invoke and log type is
automatic detect,
// then when the method invoke, the log type would be current framework
@@ -69,4 +86,8 @@ type LogFramework interface {
GenerateExtraFiles(pkgPath, debugDir string) ([]*rewrite.FileInfo,
error)
// CustomizedEnhance used to customized enhance the log framework
CustomizedEnhance(path string, curFile *dst.File, cursor
*dstutil.Cursor, allFiles []*dst.File) (map[string]string, bool)
+ // InitFunctions used to init the log framework
+ InitFunctions() []*dst.FuncDecl
+ // InitImports used to import the log framework when init functions
+ InitImports() []*dst.ImportSpec
}
diff --git a/tools/go-agent/instrument/logger/frameworks/logrus.go
b/tools/go-agent/instrument/logger/frameworks/logrus.go
index 93cbb5d..ea048ee 100644
--- a/tools/go-agent/instrument/logger/frameworks/logrus.go
+++ b/tools/go-agent/instrument/logger/frameworks/logrus.go
@@ -40,9 +40,10 @@ func (l *Logrus) Name() string {
}
func (l *Logrus) PackagePaths() map[string]*PackageConfiguration {
- return map[string]*PackageConfiguration{"github.com/sirupsen/logrus":
{NeedsHelpers: true}}
+ return map[string]*PackageConfiguration{"github.com/sirupsen/logrus":
{NeedsHelpers: true, NeedsVariables: true, NeedsChangeLoggerFunc: true}}
}
+//nolint
func (l *Logrus) AutomaticBindFunctions(fun *dst.FuncDecl) string {
// if init the output or format then the logrus would be bind
if fun.Recv == nil || len(fun.Recv.List) != 1 ||
tools.GenerateTypeNameByExp(fun.Recv.List[0].Type) != "*Logger" {
@@ -79,3 +80,11 @@ func (l *Logrus) generateReWriteFile(name, debugDir string)
*rewrite.FileInfo {
func (l *Logrus) CustomizedEnhance(path string, curFile *dst.File, cursor
*dstutil.Cursor, allFiles []*dst.File) (map[string]string, bool) {
return nil, false
}
+
+func (l *Logrus) InitFunctions() []*dst.FuncDecl {
+ return nil
+}
+
+func (l *Logrus) InitImports() []*dst.ImportSpec {
+ return nil
+}
diff --git a/tools/go-agent/instrument/logger/frameworks/logrus_adapt.go
b/tools/go-agent/instrument/logger/frameworks/logrus_adapt.go
index 3d82cc9..adba5a5 100644
--- a/tools/go-agent/instrument/logger/frameworks/logrus_adapt.go
+++ b/tools/go-agent/instrument/logger/frameworks/logrus_adapt.go
@@ -26,9 +26,9 @@ func init() {
}
func UpdateLogrusLogger(l *logrus.Logger) {
- if LogTracingContextEnable() {
+ if LogTracingContextEnable {
if _, wrapperd := l.Formatter.(*WrapFormat); !wrapperd {
- l.Formatter = Wrap(l.Formatter, LogTracingContextKey())
+ l.Formatter = Wrap(l.Formatter, LogTracingContextKey)
}
}
ChangeLogger(NewLogrusAdapter(l))
diff --git a/tools/go-agent/instrument/logger/frameworks/logrus_format.go
b/tools/go-agent/instrument/logger/frameworks/logrus_format.go
index 1d2c88b..dc6294f 100644
--- a/tools/go-agent/instrument/logger/frameworks/logrus_format.go
+++ b/tools/go-agent/instrument/logger/frameworks/logrus_format.go
@@ -18,6 +18,8 @@
package frameworks
import (
+ "fmt"
+
"github.com/sirupsen/logrus"
)
@@ -39,8 +41,30 @@ func Wrap(base logrus.Formatter, contextKey string)
*WrapFormat {
// Format logging with trace context
func (format *WrapFormat) Format(entry *logrus.Entry) ([]byte, error) {
+ var logContext fmt.Stringer
+ keys := LogReporterLabelKeys
+ if LogReporterEnable {
+ ctx := GetLogContext(true)
+ if ctx == nil {
+ return format.Base.Format(entry)
+ }
+ logContext = ctx
+ labels := make(map[string]string, len(keys))
+ for _, key := range keys {
+ for k, v := range entry.Data {
+ if k == key {
+ labels[key] = fmt.Sprintf("%v", v)
+ }
+ }
+ }
+ ReportLog(ctx, entry.Time, entry.Level.String(), entry.Message,
labels)
+ }
// append trace context
- entry.Data[format.traceContextKey] = GetLogContextString()
+ if logContext == nil {
+ entry.Data[format.traceContextKey] = GetLogContextString()
+ } else {
+ entry.Data[format.traceContextKey] = logContext.String()
+ }
return format.Base.Format(entry)
}
diff --git a/tools/go-agent/instrument/logger/frameworks/templates/init.tmpl
b/tools/go-agent/instrument/logger/frameworks/templates/init.tmpl
index 400ea4c..705d96b 100644
--- a/tools/go-agent/instrument/logger/frameworks/templates/init.tmpl
+++ b/tools/go-agent/instrument/logger/frameworks/templates/init.tmpl
@@ -1,9 +1,15 @@
-package {{.PackageName}}
-
import (
_ "unsafe"
+ "time"
+ {{- if .NeedsVariables}}
"os"
"strings"
+ {{- end}}
+
+ // customized imports
+ {{- range $key, $value := .Imports}}
+ {{$key}} {{$value}}
+ {{- end}}
)
//go:linkname {{.GetGlobalOperatorLinkMethod}} {{.GetGlobalOperatorLinkMethod}}
@@ -12,8 +18,23 @@ var {{.GetGlobalOperatorLinkMethod}} func() interface{}
//go:linkname {{.SetGlobalLoggerLinkMethod}} {{.SetGlobalLoggerLinkMethod}}
var {{.SetGlobalLoggerLinkMethod}} func(v interface{})
-var {{.LogTracingEnableFuncName}} =
{{.LogTypeInConfig.Tracing.Enabled.ToGoBoolFunction}}
-var {{.LogTracingContextKeyFuncName}} =
{{.LogTypeInConfig.Tracing.Key.ToGoStringFunction}}
+{{- if .NeedsVariables}}
+var {{.LogTracingEnableVarName}} =
{{.LogTypeInConfig.Tracing.Enabled.ToGoBoolValue}}
+var {{.LogTracingContextKeyVarName}} =
{{.LogTypeInConfig.Tracing.Key.ToGoStringValue}}
+var {{.LogReporterEnableVarName}} =
{{.LogTypeInConfig.Reporter.Enabled.ToGoBoolValue}}
+var {{.LogReporterLabelsVarName}} =
{{.LogTypeInConfig.Reporter.LabelKeys.ToGoStringListValue}}
+{{- end}}
+
+type logReporter interface {
+ ReportLog(ctx, time interface{}, level, msg string, labels
map[string]string)
+}
+var {{.LogReportFuncName}} = func(ctx interface{}, time time.Time, level, msg
string, labels map[string]string) {
+ op := {{.GetOperatorMethodName}}()
+ if op == nil {
+ return
+ }
+ op.LogReporter().(logReporter).ReportLog(ctx, time, level, msg, labels)
+}
func init() {
// for context.go getting operator
@@ -29,6 +50,7 @@ func init() {
}
// for context.go change logger
+ {{- if .NeedsChangeLoggerFunc}}
if {{.SetGlobalLoggerLinkMethod}} != nil {
logType := {{.LogTypeInConfig.Type.ToGoStringValue}}
supportLogChange := false
@@ -49,4 +71,10 @@ func init() {
{{.SetGlobalLoggerLinkMethod}}(logger)
}
}
+ {{- end}}
+
+ // init all log initiator
+ {{- range .InitFunctionNames}}
+ {{.}}()
+ {{- end}}
}
\ No newline at end of file
diff --git a/tools/go-agent/instrument/logger/frameworks/zap.go
b/tools/go-agent/instrument/logger/frameworks/zap.go
index e9e02bb..6af67d3 100644
--- a/tools/go-agent/instrument/logger/frameworks/zap.go
+++ b/tools/go-agent/instrument/logger/frameworks/zap.go
@@ -19,6 +19,7 @@ package frameworks
import (
"fmt"
+ "go/token"
"path/filepath"
"github.com/apache/skywalking-go/tools/go-agent/instrument/plugins/rewrite"
@@ -30,17 +31,17 @@ import (
const (
zapPackageRootPath = "go.uber.org/zap"
+ zapPackageCorePath = "go.uber.org/zap/zapcore"
LoggerTypeName = "*Logger"
)
var zapStaticFuncNames = []string{
"New", "NewNop", "NewProduction", "NewDevelopment", "NewExample",
}
-var zapLoggerMethodNames = []string{
- "Log", "Debug", "Info", "Warn", "Error", "Panic", "Fatal", "DPanic",
-}
type Zap struct {
+ initFunction *dst.FuncDecl
+ initImports []*dst.ImportSpec
}
func NewZap() *Zap {
@@ -53,7 +54,8 @@ func (z *Zap) Name() string {
func (z *Zap) PackagePaths() map[string]*PackageConfiguration {
return map[string]*PackageConfiguration{
- zapPackageRootPath: {NeedsHelpers: true},
+ zapPackageRootPath: {NeedsHelpers: true, NeedsVariables: true,
NeedsChangeLoggerFunc: true},
+ zapPackageCorePath: {NeedsHelpers: true, NeedsVariables: false,
NeedsChangeLoggerFunc: false},
}
}
@@ -77,98 +79,136 @@ func (z *Zap) AutomaticBindFunctions(fun *dst.FuncDecl)
string {
}
func (z *Zap) GenerateExtraFiles(pkgPath, debugDir string)
([]*rewrite.FileInfo, error) {
+ var path string
if pkgPath == zapPackageRootPath {
- file, err := FrameworkFS.ReadFile("zap_adapt.go")
- if err != nil {
- panic(fmt.Errorf("get zap file error: %v", err))
- }
+ path = "zap_root.go"
+ } else if pkgPath == zapPackageCorePath {
+ path = "zap_core.go"
+ }
- result := make([]*rewrite.FileInfo, 0)
- if debugDir == "" {
- result = append(result, rewrite.NewFile("zap",
"zap_adapt.go", string(file)))
- } else {
- result = append(result, rewrite.NewFileWithDebug("zap",
"zap_adapt.go", string(file),
- filepath.Join(debugDir, "tools", "go-agent",
"instrument", "logger", "frameworks")))
- }
+ file, err := FrameworkFS.ReadFile(path)
+ if err != nil {
+ panic(fmt.Errorf("get zap file error: %v", err))
+ }
- return result, nil
+ result := make([]*rewrite.FileInfo, 0)
+ if debugDir == "" {
+ result = append(result, rewrite.NewFile("zap", path,
string(file)))
+ } else {
+ result = append(result, rewrite.NewFileWithDebug("zap", path,
string(file),
+ filepath.Join(debugDir, "tools", "go-agent",
"instrument", "logger", "frameworks")))
}
- return nil, nil
+ return result, nil
}
+//nolint
func (z *Zap) CustomizedEnhance(path string, curFile *dst.File, cursor
*dstutil.Cursor, allFiles []*dst.File) (map[string]string, bool) {
- fun, ok := cursor.Node().(*dst.FuncDecl)
- if !ok {
- return nil, false
- }
+ switch n := cursor.Node().(type) {
+ case *dst.TypeSpec:
+ // adding the context field into entry
+ st, ok := n.Type.(*dst.StructType)
+ if !ok || st.Fields == nil || n.Name == nil {
+ return nil, false
+ }
+ if n.Name.Name == "CheckedEntry" {
+ st.Fields.List = append(st.Fields.List,
+ // tracing context object
+ &dst.Field{Names:
[]*dst.Ident{dst.NewIdent("SWContext")}, Type: dst.NewIdent("interface{}")},
+ // tracing context field
+ &dst.Field{Names:
[]*dst.Ident{dst.NewIdent("SWContextField")}, Type: &dst.StarExpr{X:
dst.NewIdent("Field")}},
+ // existing fields needs to be added into, such
as generate from log.With("key", "value")
+ &dst.Field{Names:
[]*dst.Ident{dst.NewIdent("SWFields")}, Type: &dst.ArrayType{Elt:
dst.NewIdent("Field")}},
+ )
+ curFile.Decls = append(curFile.Decls, &dst.GenDecl{
+ Tok: token.VAR,
+ Specs: []dst.Spec{
+ &dst.ValueSpec{Names: []*dst.Ident{
+
dst.NewIdent("SWReporterEnable"),
+ dst.NewIdent("SWLogEnable"),
+ }, Type: dst.NewIdent("bool")},
+ &dst.ValueSpec{Names: []*dst.Ident{
+
dst.NewIdent("SWReporterLabelKeys"),
+ }, Type: dst.NewIdent("[]string")},
+ &dst.ValueSpec{Names: []*dst.Ident{
+
dst.NewIdent("SWLogTracingContextKey"),
+ }, Type: dst.NewIdent("string")},
+ &dst.ValueSpec{Names: []*dst.Ident{
+ dst.NewIdent("SWFields"),
+ }, Type: dst.NewIdent("[]Field")},
+ },
+ })
+ return nil, true
+ }
+ if n.Name.Name == "Logger" {
+ st.Fields.List = append(st.Fields.List,
+ &dst.Field{Names:
[]*dst.Ident{dst.NewIdent("SWFields")}, Type: dst.NewIdent("[]zapcore.Field")})
+ return nil, true
+ }
+ case *dst.FuncDecl:
+ // enhance the method which check the log and generate the entry
+ if n.Recv != nil && len(n.Recv.List) == 1 &&
tools.GenerateTypeNameByExp(n.Recv.List[0].Type) == "*Logger" &&
+ n.Name.Name == "check" &&
+ n.Type.Results != nil && len(n.Type.Results.List) > 0 &&
+
tools.GenerateTypeNameByExp(n.Type.Results.List[0].Type) ==
"*zapcore.CheckedEntry" {
+ entryName :=
tools.EnhanceParameterNames(n.Type.Results, true)[0].Name
+ recvName := tools.EnhanceParameterNames(n.Recv,
true)[0].Name
+
+ // init the zapcore variables
+ z.initFunction =
tools.GoStringToDecls(fmt.Sprintf(`func initZapCore() {
+zapcore.SWReporterEnable = %s
+zapcore.SWReporterLabelKeys = %s
+zapcore.SWLogEnable = %s
+}`, "LogReporterEnable", "LogReporterLabelKeys",
"LogTracingContextEnable"))[0].(*dst.FuncDecl)
+ z.initImports = []*dst.ImportSpec{
+ {Path: &dst.BasicLit{Kind: token.STRING, Value:
`"go.uber.org/zap/zapcore"`}},
+ }
+
+ return z.enhanceMethod(n, fmt.Sprintf("defer func() {if
%s != nil {"+
+ "%s.SWContext, %s.SWContextField = %s%s(%s);
%s.SWFields = %s.SWFields;}}()", entryName,
+ entryName, entryName,
rewrite.StaticMethodPrefix, "ZapTracingContextEnhance", entryName, entryName,
recvName)), true
+ }
- // enhance the *Logger.Info, Warn, etc. method for add tracing context
field
- if fun.Recv == nil || len(fun.Recv.List) != 1 || fun.Type.Params == nil
|| len(fun.Type.Params.List) <= 1 {
- return nil, false
- }
+ if n.Recv != nil && len(n.Recv.List) == 1 && n.Name.Name ==
"With" &&
+ n.Type.Params != nil && len(n.Type.Params.List) == 1 &&
+ tools.GenerateTypeNameByExp(n.Recv.List[0].Type) ==
"*Logger" && tools.GenerateTypeNameByExp(n.Type.Params.List[0].Type) ==
"[]Field" {
+ recvs := tools.EnhanceParameterNames(n.Recv, false)
+ parameters :=
tools.EnhanceParameterNames(n.Type.Params, false)
+ results := tools.EnhanceParameterNames(n.Type.Results,
true)
- if tools.GenerateTypeNameByExp(fun.Recv.List[0].Type) == LoggerTypeName
{
- return z.enhanceLoggerTracingContext(fun)
- } else if tools.GenerateTypeNameByExp(fun.Recv.List[0].Type) ==
"*SugaredLogger" {
- return z.enhanceSugaredLoggerTracingContext(fun)
- }
+ return z.enhanceMethod(n, fmt.Sprintf(`defer func() {if
%s != nil { %s.SWFields = %sZap%s(%s, %s.SWFields) }}()`,
+ results[0].Name, results[0].Name,
rewrite.StaticMethodPrefix, "KnownFieldFilter", parameters[0].Name,
recvs[0].Name)), true
+ }
+ // enhance the method which write the checked entry context
+ if n.Recv != nil && len(n.Recv.List) == 1 &&
tools.GenerateTypeNameByExp(n.Recv.List[0].Type) == "*CheckedEntry" &&
+ n.Name.Name == "Write" &&
+ n.Type.Params != nil && len(n.Type.Params.List) == 1 &&
+ tools.GenerateTypeNameByExp(n.Type.Params.List[0].Type)
== "[]Field" {
+ recvs := tools.EnhanceParameterNames(n.Recv, false)
+ parameters :=
tools.EnhanceParameterNames(n.Type.Params, false)
+ return z.enhanceMethod(n, fmt.Sprintf(`if %s != nil {
%s = %sZapcore%s(%s, %s, %s.SWFields, %s.SWContext, %s.SWContextField,
SWReporterEnable, SWLogEnable, SWReporterLabelKeys) }`,
+ recvs[0].Name, parameters[0].Name,
rewrite.StaticMethodPrefix, "ReportLogFromZapEntry", recvs[0].Name,
+ parameters[0].Name, recvs[0].Name,
recvs[0].Name, recvs[0].Name)), true
+ }
+ }
return nil, false
}
-func (z *Zap) enhanceSugaredLoggerTracingContext(fun *dst.FuncDecl)
(map[string]string, bool) {
- if fun.Name.Name != "log" {
- return nil, false
- }
- parameters := tools.EnhanceParameterNames(fun.Type.Params, false)
- var contextParameter *tools.ParameterInfo
- for _, p := range parameters {
- if p.Name == "context" && p.TypeName == "[]interface{}" {
- contextParameter = p
- break
- }
- }
- if contextParameter == nil {
- return nil, false
- }
+func (z *Zap) enhanceMethod(fun *dst.FuncDecl, goCode string)
map[string]string {
funcID := tools.BuildFuncIdentity(zapPackageRootPath, fun)
replaceKey := fmt.Sprintf("//goagent:enhance_%s", funcID)
- replaceValue := fmt.Sprintf("%s = %s%s(%s)",
- contextParameter.Name, rewrite.StaticMethodPrefix,
"ZapAddZapTracingInterfaceField", contextParameter.Name)
fun.Body.Decs.Lbrace.Prepend("\n", replaceKey)
- return map[string]string{replaceKey: replaceValue}, true
+ return map[string]string{replaceKey: goCode}
}
-func (z *Zap) enhanceLoggerTracingContext(fun *dst.FuncDecl)
(map[string]string, bool) {
- foundMethod := false
-
- for _, name := range zapLoggerMethodNames {
- if fun.Name.Name == name {
- foundMethod = true
- break
- }
- }
- if !foundMethod {
- return nil, false
- }
-
- parameterNames := tools.EnhanceParameterNames(fun.Type.Params, false)
- var fieldParameter *tools.ParameterInfo
- for _, p := range parameterNames {
- if p.TypeName == "...Field" {
- fieldParameter = p
- break
- }
- }
- if fieldParameter == nil {
- return nil, false
+func (z *Zap) InitFunctions() []*dst.FuncDecl {
+ if z.initFunction != nil {
+ return []*dst.FuncDecl{z.initFunction}
}
- funcID := tools.BuildFuncIdentity(zapPackageRootPath, fun)
- replaceKey := fmt.Sprintf("//goagent:enhance_%s", funcID)
- replaceValue := fmt.Sprintf("%s = %s%s(%s)",
- fieldParameter.Name, rewrite.StaticMethodPrefix,
"ZapAddZapTracingField", fieldParameter.Name)
- fun.Body.Decs.Lbrace.Prepend("\n", replaceKey)
+ return nil
+}
- return map[string]string{replaceKey: replaceValue}, true
+func (z *Zap) InitImports() []*dst.ImportSpec {
+ return z.initImports
}
diff --git a/tools/go-agent/instrument/logger/frameworks/zap_core.go
b/tools/go-agent/instrument/logger/frameworks/zap_core.go
new file mode 100644
index 0000000..47f72a6
--- /dev/null
+++ b/tools/go-agent/instrument/logger/frameworks/zap_core.go
@@ -0,0 +1,61 @@
+// 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 frameworks
+
+import (
+ "fmt"
+
+ "go.uber.org/zap/zapcore"
+)
+
+func ReportLogFromZapEntry(entry *zapcore.CheckedEntry, fields, needs
[]zapcore.Field, tracingContext interface{},
+ tracingContextField *zapcore.Field, reporterEnable, logEnable bool,
reportLabelsKeys []string) []zapcore.Field {
+ if reporterEnable && tracingContext != nil {
+ labels := make(map[string]string, len(reportLabelsKeys))
+ for _, key := range reportLabelsKeys {
+ for _, f := range fields {
+ if f.Key == key {
+ if k, v :=
generateLabelKeyValueFromField(f); k != "" {
+ labels[k] = v
+ }
+ }
+ }
+ }
+ for _, f := range needs {
+ if k, v := generateLabelKeyValueFromField(f); k != "" {
+ labels[k] = v
+ }
+ }
+ ReportLog(tracingContext, entry.Time, entry.Level.String(),
entry.Message, labels)
+ }
+ if logEnable && tracingContextField != nil {
+ fields = append(fields, *tracingContextField)
+ }
+ return fields
+}
+
+func generateLabelKeyValueFromField(field zapcore.Field) (key, value string) {
+ if field.Interface != nil {
+ return field.Key, fmt.Sprintf("%v", field.Interface)
+ } else if field.Integer > 0 {
+ return field.Key, fmt.Sprintf("%d", field.Integer)
+ } else if field.String != "" {
+ return field.Key, field.String
+ }
+ return "", ""
+}
diff --git a/tools/go-agent/instrument/logger/frameworks/zap_adapt.go
b/tools/go-agent/instrument/logger/frameworks/zap_root.go
similarity index 75%
rename from tools/go-agent/instrument/logger/frameworks/zap_adapt.go
rename to tools/go-agent/instrument/logger/frameworks/zap_root.go
index 1c6ae30..aca4583 100644
--- a/tools/go-agent/instrument/logger/frameworks/zap_adapt.go
+++ b/tools/go-agent/instrument/logger/frameworks/zap_root.go
@@ -21,6 +21,7 @@ import (
"fmt"
"go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
)
type ZapLogContextStringGenerator struct {
@@ -34,18 +35,29 @@ func UpdateZapLogger(l *zap.Logger) {
ChangeLogger(NewZapAdapter(l))
}
-func AddZapTracingField(fields []zap.Field) []zap.Field {
- if LogTracingContextEnable() {
- return append(fields, zap.String(LogTracingContextKey(),
GetLogContextString()))
+func TracingContextEnhance(entry *zapcore.CheckedEntry) (interface{},
*zapcore.Field) {
+ var getEndpoint = LogReporterEnable
+ if LogReporterEnable || LogTracingContextEnable {
+ ctx := GetLogContext(getEndpoint)
+ f := zap.String(LogTracingContextKey, ctx.String())
+ return ctx, &f
}
- return fields
+ return nil, nil
}
-func AddZapTracingInterfaceField(fields []interface{}) []interface{} {
- if LogTracingContextEnable() {
- return append(fields, zap.String(LogTracingContextKey(),
GetLogContextString()))
+func KnownFieldFilter(fs, existingFields []zapcore.Field) []zapcore.Field {
+ keys := LogReporterLabelKeys
+ res := make([]zapcore.Field, 0)
+ for _, k := range keys {
+ for _, f := range fs {
+ if f.Key == k {
+ res = append(res, f)
+ }
+ }
}
- return fields
+ // copy original data
+ res = append(res, existingFields...)
+ return res
}
type ZapAdapter struct {
diff --git a/tools/go-agent/instrument/logger/instrument.go
b/tools/go-agent/instrument/logger/instrument.go
index 7e3a78d..38e9caa 100644
--- a/tools/go-agent/instrument/logger/instrument.go
+++ b/tools/go-agent/instrument/logger/instrument.go
@@ -187,13 +187,15 @@ func (i *Instrument) WriteExtraFiles(dir string)
([]string, error) {
return nil, err
}
files = append(files, generateExtraFiles...)
+ if i.packageConf.NeedsHelpers {
+ files = append(files, rewrite.NewFile(packageName,
"skywalking_init.go",
+ i.generateInitLoggerFileContent(packageName)))
+ }
extraFiles, err := ctx.MultipleFilesWithWritten("skywalking_", dir,
packageName, files)
if err != nil {
return nil, err
}
- if i.packageConf.NeedsHelpers {
- extraFiles = append(extraFiles, i.generateInitLoggerFile(dir,
packageName))
- }
+
return extraFiles, nil
}
@@ -222,40 +224,72 @@ func (i *Instrument) writeDelegatorFile(pkgName string)
(string, error) {
return tools.GenerateDSTFileContent(delegator, nil)
}
-func (i *Instrument) generateInitLoggerFile(dir, pkgName string) string {
+func (i *Instrument) generateInitLoggerFileContent(pkgName string) string {
initTmpl, err := frameworks.FrameworkFS.ReadFile("templates/init.tmpl")
if err != nil {
panic(fmt.Sprintf("cannot found init template in logger
framerwork: %v", err))
}
- file, err := tools.WriteFile(dir, "skywalking_init.go",
tools.ExecuteTemplate(string(initTmpl), struct {
- PackageName string
- GetGlobalOperatorLinkMethod string
- SetGlobalLoggerLinkMethod string
- OperatorTypeName string
- LogTypeInConfig *config.Log
- ConfigTypeAutomaticValue string
- CurrentLogTypeName string
- GetOperatorMethodName string
- ChangeLoggerMethodName string
- LogTracingEnableFuncName string
- LogTracingContextKeyFuncName string
+
+ initFunctions := i.framework.InitFunctions()
+ initFuncNames := make([]string, 0)
+ for _, initFunc := range initFunctions {
+ initFuncNames = append(initFuncNames, initFunc.Name.Name)
+ }
+ importsMap := make(map[string]string)
+ for _, imp := range i.framework.InitImports() {
+ name := filepath.Base(strings.TrimSuffix(imp.Path.Value, "\""))
+ if imp.Name != nil && imp.Name.Name != "" {
+ name = imp.Name.Name
+ }
+ importsMap[name] = imp.Path.Value
+ }
+ initDecls :=
tools.GoStringToDecls(tools.ExecuteTemplate(string(initTmpl), struct {
+ Imports map[string]string
+ NeedsVariables bool
+ NeedsChangeLoggerFunc bool
+ GetGlobalOperatorLinkMethod string
+ SetGlobalLoggerLinkMethod string
+ OperatorTypeName string
+ LogTypeInConfig *config.Log
+ ConfigTypeAutomaticValue string
+ CurrentLogTypeName string
+ GetOperatorMethodName string
+ ChangeLoggerMethodName string
+ LogTracingEnableVarName string
+ LogTracingContextKeyVarName string
+ LogReporterEnableVarName string
+ LogReporterLabelsVarName string
+ LogReportFuncName string
+ InitFunctionNames []string
}{
- PackageName: pkgName,
- GetGlobalOperatorLinkMethod: consts.GlobalTracerGetMethodName,
- SetGlobalLoggerLinkMethod: consts.GlobalLoggerSetMethodName,
- OperatorTypeName: rewrite.TypePrefix +
i.generatePackageNameWithTitle() + "Operator",
- LogTypeInConfig: &config.GetConfig().Log,
- ConfigTypeAutomaticValue: config.ConfigTypeAutomatic,
- CurrentLogTypeName: i.framework.Name(),
- GetOperatorMethodName: rewrite.VarPrefix +
i.generatePackageNameWithTitle() + "GetOperator",
- ChangeLoggerMethodName: rewrite.VarPrefix +
i.generatePackageNameWithTitle() + "ChangeLogger",
- LogTracingEnableFuncName: rewrite.StaticMethodPrefix +
i.generatePackageNameWithTitle() + "LogTracingContextEnable",
- LogTracingContextKeyFuncName: rewrite.StaticMethodPrefix +
i.generatePackageNameWithTitle() + "LogTracingContextKey",
+ Imports: importsMap,
+ NeedsVariables: i.packageConf.NeedsVariables,
+ NeedsChangeLoggerFunc:
i.packageConf.NeedsChangeLoggerFunc,
+ GetGlobalOperatorLinkMethod: consts.GlobalTracerGetMethodName,
+ SetGlobalLoggerLinkMethod: consts.GlobalLoggerSetMethodName,
+ OperatorTypeName: "Operator",
+ LogTypeInConfig: &config.GetConfig().Log,
+ ConfigTypeAutomaticValue: config.ConfigTypeAutomatic,
+ CurrentLogTypeName: i.framework.Name(),
+ GetOperatorMethodName: "GetOperator",
+ ChangeLoggerMethodName: "ChangeLogger",
+ LogTracingEnableVarName: "LogTracingContextEnable",
+ LogTracingContextKeyVarName: "LogTracingContextKey",
+ LogReporterEnableVarName: "LogReporterEnable",
+ LogReporterLabelsVarName: "LogReporterLabelKeys",
+ LogReportFuncName: "ReportLog",
+ InitFunctionNames: initFuncNames,
}))
- if err != nil {
+ for _, f := range initFunctions {
+ initDecls = append(initDecls, f)
+ }
+
+ f := &dst.File{Name: dst.NewIdent(pkgName), Decls: initDecls}
+ if c, err1 := tools.GenerateDSTFileContent(f, nil); err1 != nil {
panic(fmt.Errorf("generate logger init file error: %v", err))
+ } else {
+ return c
}
- return file
}
func (i *Instrument) generatePackageNameWithTitle() string {
diff --git a/tools/go-agent/instrument/plugins/rewrite/var.go
b/tools/go-agent/instrument/plugins/rewrite/var.go
index a7d3bde..4e7467a 100644
--- a/tools/go-agent/instrument/plugins/rewrite/var.go
+++ b/tools/go-agent/instrument/plugins/rewrite/var.go
@@ -28,8 +28,8 @@ func (c *Context) Var(val *dst.ValueSpec, onlyName bool) {
oldName := val.Names[0].Name
if !c.alreadyGenerated(oldName) {
val.Names[0] = dst.NewIdent(fmt.Sprintf("%s%s%s",
VarPrefix, c.currentPackageTitle, oldName))
- c.rewriteMapping.addVarMapping(oldName,
val.Names[0].Name)
}
+ c.rewriteMapping.addVarMapping(oldName, val.Names[0].Name)
}
if onlyName {
return