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 b75bbbd Support native SQL framework plugin with MySQL driver (#65)
b75bbbd is described below
commit b75bbbd812bcb55c2a041b4d0afe167453babaef
Author: mrproliu <[email protected]>
AuthorDate: Fri Jun 16 12:25:04 2023 +0000
Support native SQL framework plugin with MySQL driver (#65)
---
.github/workflows/plugin-tests.yaml | 1 +
CHANGES.md | 1 +
docs/en/agent/plugin-configurations.md | 1 +
docs/en/agent/support-plugins.md | 4 +-
go.work | 2 +
plugins/core/context.go | 4 +
plugins/core/instrument/method.go | 52 ++++-
.../tools/types.go => plugins/sql/entry/config.go | 20 +-
.../types.go => plugins/sql/entry/conn_begin_tx.go | 24 +-
.../types.go => plugins/sql/entry/conn_exec.go | 24 +-
.../types.go => plugins/sql/entry/conn_ping.go | 24 +-
.../types.go => plugins/sql/entry/conn_prepare.go | 24 +-
.../types.go => plugins/sql/entry/conn_query.go | 24 +-
.../types.go => plugins/sql/entry/conn_raw.go | 24 +-
.../types.go => plugins/sql/entry/db_begin_tx.go | 24 +-
plugins/sql/entry/db_conn.go | 63 ++++++
.../tools/types.go => plugins/sql/entry/db_exec.go | 24 +-
.../tools/types.go => plugins/sql/entry/db_ping.go | 24 +-
.../types.go => plugins/sql/entry/db_prepare.go | 24 +-
.../types.go => plugins/sql/entry/db_query.go | 24 +-
plugins/sql/entry/general.go | 204 +++++++++++++++++
plugins/sql/entry/instance_open.go | 58 +++++
plugins/sql/entry/instrument.go | 230 +++++++++++++++++++
plugins/sql/entry/span.go | 59 +++++
plugins/sql/entry/stmt_exec.go | 50 +++++
plugins/sql/entry/stmt_query.go | 50 +++++
.../types.go => plugins/sql/entry/tx_commit.go | 36 ++-
plugins/sql/entry/tx_exec.go | 51 +++++
.../types.go => plugins/sql/entry/tx_prepare.go | 24 +-
plugins/sql/entry/tx_query.go | 51 +++++
.../types.go => plugins/sql/entry/tx_rollback.go | 36 ++-
.../tools/types.go => plugins/sql/entry/tx_stmt.go | 29 +--
plugins/sql/go.mod | 5 +
plugins/sql/mysql/instrument.go | 67 ++++++
.../sql/mysql/parse_interceptor.go | 44 +++-
test/plugins/scenarios/gorm/config/excepted.yml | 106 +++++++--
test/plugins/scenarios/mongo/plugin.yml | 1 -
.../{mongo/plugin.yml => mysql/bin/startup.sh} | 39 +---
test/plugins/scenarios/mysql/config/excepted.yml | 250 +++++++++++++++++++++
test/plugins/scenarios/mysql/go.mod | 5 +
test/plugins/scenarios/mysql/go.sum | 2 +
test/plugins/scenarios/mysql/main.go | 161 +++++++++++++
test/plugins/scenarios/{mongo => mysql}/plugin.yml | 42 ++--
tools/go-agent/config/agent.default.yaml | 5 +-
tools/go-agent/instrument/instrument.go | 7 +
tools/go-agent/instrument/plugins/register.go | 6 +
tools/go-agent/tools/enhancement.go | 23 ++
tools/go-agent/tools/types.go | 2 +-
48 files changed, 1756 insertions(+), 299 deletions(-)
diff --git a/.github/workflows/plugin-tests.yaml
b/.github/workflows/plugin-tests.yaml
index 71f9895..96f6496 100644
--- a/.github/workflows/plugin-tests.yaml
+++ b/.github/workflows/plugin-tests.yaml
@@ -78,6 +78,7 @@ jobs:
- kratosv2
- microv4
- mongo
+ - mysql
- plugin_exclusion
steps:
- uses: actions/checkout@v2
diff --git a/CHANGES.md b/CHANGES.md
index 5ff3eab..e02b0fc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -13,6 +13,7 @@ Release Notes.
* 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).
#### Documentation
diff --git a/docs/en/agent/plugin-configurations.md
b/docs/en/agent/plugin-configurations.md
index 5eabfb2..088dd89 100644
--- a/docs/en/agent/plugin-configurations.md
+++ b/docs/en/agent/plugin-configurations.md
@@ -4,3 +4,4 @@
|--------------------------------|-------------------------------------------------------|---------------|----------------------------------------------------------------|
| http.server_collect_parameters |
SW_AGENT_PLUGIN_CONFIG_HTTP_SERVER_COLLECT_PARAMETERS | false | Collect
the parameters of the HTTP request on the server side. |
| mongo.collect_statement |
SW_AGENT_PLUGIN_CONFIG_MONGO_COLLECT_STATEMENT | false | Collect
the statement of the MongoDB request. |
+| sql.collect_parameter |
SW_AGENT_PLUGIN_CONFIG_SQL_COLLECT_PARAMETER | false | Collect
the parameter of the SQL request. |
diff --git a/docs/en/agent/support-plugins.md b/docs/en/agent/support-plugins.md
index 174efb9..8ad0cab 100644
--- a/docs/en/agent/support-plugins.md
+++ b/docs/en/agent/support-plugins.md
@@ -13,6 +13,8 @@
* Database Client
* `gorm`: [GORM](https://github.com/go-gorm/gorm) tested v1.22.0 to v1.25.1.
* [MySQL Driver](https://github.com/go-gorm/mysql)
- * `mongo`: [Mongo](https://github.com/mongodb/mongo-go-driver) tested
v1.11.0 to v1.11.7.
+ * `mongo`: [Mongo](https://github.com/mongodb/mongo-go-driver) tested
v1.11.1 to v1.11.7.
+ * `sql`: [Native SQL](https://pkg.go.dev/database/sql) tested go v1.17 to go
v1.20.
+ * [MySQL Driver](https://github.com/go-sql-driver/mysql) tested v1.4.0 to
v1.7.1.
* Cache Client
* `go-redisv9`: [go-redis](https://github.com/redis/go-redis) tested v9.0.3
to v9.0.5.
\ No newline at end of file
diff --git a/go.work b/go.work
index fcb85b4..30fefe5 100644
--- a/go.work
+++ b/go.work
@@ -14,6 +14,7 @@ use (
./plugins/kratosv2
./plugins/microv4
./plugins/mongo
+ ./plugins/sql
./test/benchmark-codebase/consumer
./test/benchmark-codebase/provider
@@ -30,6 +31,7 @@ use (
./test/plugins/scenarios/kratosv2
./test/plugins/scenarios/microv4
./test/plugins/scenarios/mongo
+ ./test/plugins/scenarios/mysql
./test/plugins/scenarios/plugin_exclusion
diff --git a/plugins/core/context.go b/plugins/core/context.go
index 03ec73b..d1dae7c 100644
--- a/plugins/core/context.go
+++ b/plugins/core/context.go
@@ -89,5 +89,9 @@ func (r *RuntimeContext) Get(key string) interface{} {
}
func (r *RuntimeContext) Set(key string, value interface{}) {
+ if value == nil {
+ delete(r.data, key)
+ return
+ }
r.data[key] = value
}
diff --git a/plugins/core/instrument/method.go
b/plugins/core/instrument/method.go
index ea1734b..d726057 100644
--- a/plugins/core/instrument/method.go
+++ b/plugins/core/instrument/method.go
@@ -22,34 +22,28 @@ import "github.com/dave/dst"
// WithArgsCount filter methods with specific count of arguments.
func WithArgsCount(argsCount int) MethodFilterOption {
return func(method *dst.FuncDecl, files []*dst.File) bool {
- return (method.Type.Params == nil &&
len(method.Type.Params.List) == argsCount) || (len(method.Type.Params.List) ==
argsCount)
+ return fieldListParameterCount(method.Type.Params) == argsCount
}
}
// WithResultCount filter methods with specific count of results.
func WithResultCount(resultCount int) MethodFilterOption {
return func(decl *dst.FuncDecl, files []*dst.File) bool {
- return (decl.Type.Results == nil && resultCount == 0) ||
(len(decl.Type.Results.List) == resultCount)
+ return fieldListParameterCount(decl.Type.Results) == resultCount
}
}
// WithArgType filter methods with specific type of the index of the argument.
func WithArgType(argIndex int, dataType string) MethodFilterOption {
return func(decl *dst.FuncDecl, files []*dst.File) bool {
- if decl.Type.Params == nil || len(decl.Type.Params.List) <=
argIndex {
- return false
- }
- return verifyTypeName(decl.Type.Params.List[argIndex].Type,
dataType)
+ return verifyTypeSameInFieldList(decl.Type.Params, argIndex,
dataType)
}
}
// WithResultType filter methods with specific type of the index of the result.
func WithResultType(argIndex int, dataType string) MethodFilterOption {
return func(decl *dst.FuncDecl, files []*dst.File) bool {
- if decl.Type.Results == nil || len(decl.Type.Results.List) <=
argIndex {
- return false
- }
- return verifyTypeName(decl.Type.Results.List[argIndex].Type,
dataType)
+ return verifyTypeSameInFieldList(decl.Type.Results, argIndex,
dataType)
}
}
@@ -69,3 +63,41 @@ func WithReceiverType(dataType string) MethodFilterOption {
return verifyTypeName(decl.Recv.List[0].Type, dataType)
}
}
+
+func fieldListParameterCount(fieldList *dst.FieldList) int {
+ if fieldList == nil || len(fieldList.List) == 0 {
+ return 0
+ }
+ res := 0
+ for _, f := range fieldList.List {
+ if len(f.Names) == 0 {
+ res++
+ continue
+ }
+ res += len(f.Names)
+ }
+ return res
+}
+
+func verifyTypeSameInFieldList(fieldList *dst.FieldList, inx int, typeStr
string) bool {
+ if inx >= fieldListParameterCount(fieldList) {
+ return false
+ }
+ realInx := 0
+ for _, f := range fieldList.List {
+ if len(f.Names) == 0 {
+ if realInx == inx {
+ return verifyTypeName(f.Type, typeStr)
+ }
+ realInx++
+ continue
+ }
+ for i := 0; i < len(f.Names); i++ {
+ if realInx == inx {
+ return verifyTypeName(f.Type, typeStr)
+ }
+ realInx++
+ }
+ }
+ return false
+}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/config.go
similarity index 64%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/config.go
index aabda3b..5fd1e90 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/config.go
@@ -15,21 +15,9 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
-
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
-}
-
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+//skywalking:config
+var config struct {
+ CollectParameter bool `config:"collect_parameter"`
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/conn_begin_tx.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/conn_begin_tx.go
index aabda3b..410646c 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/conn_begin_tx.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ConnBeginTXInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ConnBeginTXInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralBeginTxBeforeInvoke(invocation, "Conn/BeginTx")
+}
+
+func (n *ConnBeginTXInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralBeginTxAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/conn_exec.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/conn_exec.go
index aabda3b..d441809 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/conn_exec.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ConnExecInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ConnExecInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralExecBeforeInvoke(invocation, "Conn/Exec")
+}
+
+func (n *ConnExecInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralExecAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/conn_ping.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/conn_ping.go
index aabda3b..b5731d0 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/conn_ping.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ConnPingInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ConnPingInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralPingBeforeInvoke(invocation, "Conn/Ping")
+}
+
+func (n *ConnPingInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralPingAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/conn_prepare.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/conn_prepare.go
index aabda3b..acc91ce 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/conn_prepare.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ConnPrepareInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ConnPrepareInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralPrepareBeforeInvoke(invocation, "Conn/Prepare")
+}
+
+func (n *ConnPrepareInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralPrepareAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/conn_query.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/conn_query.go
index aabda3b..d4819d8 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/conn_query.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ConnQueryInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ConnQueryInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralQueryBeforeInvoke(invocation, "Conn/Query")
+}
+
+func (n *ConnQueryInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralQueryAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/conn_raw.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/conn_raw.go
index aabda3b..6387bd3 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/conn_raw.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ConnRawInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ConnRawInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralRawBeforeInvoke(invocation, "Conn/Raw")
+}
+
+func (n *ConnRawInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralRawAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/db_begin_tx.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/db_begin_tx.go
index aabda3b..55910bf 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/db_begin_tx.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type BeginTXInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *BeginTXInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralBeginTxBeforeInvoke(invocation, "BeginTx")
+}
+
+func (n *BeginTXInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralBeginTxAfterInvoke(invocation, results...)
}
diff --git a/plugins/sql/entry/db_conn.go b/plugins/sql/entry/db_conn.go
new file mode 100644
index 0000000..c3c5594
--- /dev/null
+++ b/plugins/sql/entry/db_conn.go
@@ -0,0 +1,63 @@
+// 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 (
+ "database/sql"
+
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type ConnInterceptor struct {
+}
+
+type connInfo struct {
+ instance InstanceInfo
+ span tracing.Span
+}
+
+func (n *ConnInterceptor) BeforeInvoke(invocation operator.Invocation) error {
+ span, info, err := createLocalSpan(invocation.CallerInstance(), "Conn")
+ if err != nil || span == nil {
+ return err
+ }
+ invocation.SetContext(&connInfo{
+ instance: info,
+ span: span,
+ })
+ return nil
+}
+
+func (n *ConnInterceptor) AfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ // if contains error, then record it
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(*connInfo).span.Error(err.Error())
+ }
+ ctx.(*connInfo).span.End()
+
+ // propagate the instance info
+ if instance, ok := results[0].(*sql.Conn); ok && instance != nil {
+
results[0].(operator.EnhancedInstance).SetSkyWalkingDynamicField(ctx.(*connInfo).instance)
+ }
+ return nil
+}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/db_exec.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/db_exec.go
index aabda3b..7ca779d 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/db_exec.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type ExecInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *ExecInterceptor) BeforeInvoke(invocation operator.Invocation) error {
+ return GeneralExecBeforeInvoke(invocation, "Exec")
+}
+
+func (n *ExecInterceptor) AfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ return GeneralExecAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/db_ping.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/db_ping.go
index aabda3b..86c6394 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/db_ping.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type PingInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *PingInterceptor) BeforeInvoke(invocation operator.Invocation) error {
+ return GeneralPingBeforeInvoke(invocation, "Ping")
+}
+
+func (n *PingInterceptor) AfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ return GeneralPingAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/db_prepare.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/db_prepare.go
index aabda3b..5dfbf71 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/db_prepare.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type PrepareInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *PrepareInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralPrepareBeforeInvoke(invocation, "Prepare")
+}
+
+func (n *PrepareInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralPrepareAfterInvoke(invocation, results...)
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/db_query.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/db_query.go
index aabda3b..6e27045 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/db_query.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type QueryInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *QueryInterceptor) BeforeInvoke(invocation operator.Invocation) error {
+ return GeneralQueryBeforeInvoke(invocation, "Query")
+}
+
+func (n *QueryInterceptor) AfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ return GeneralQueryAfterInvoke(invocation, results...)
}
diff --git a/plugins/sql/entry/general.go b/plugins/sql/entry/general.go
new file mode 100644
index 0000000..a51245e
--- /dev/null
+++ b/plugins/sql/entry/general.go
@@ -0,0 +1,204 @@
+// 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 (
+ "database/sql"
+ "fmt"
+
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type PrepareInfo struct {
+ instance InstanceInfo
+ span tracing.Span
+}
+
+func GeneralPrepareBeforeInvoke(invocation operator.Invocation, method string)
error {
+ span, info, err := createLocalSpan(invocation.CallerInstance(), method,
+ tracing.WithTag(tracing.TagDBStatement,
invocation.Args()[1].(string)))
+ if err != nil || span == nil {
+ return err
+ }
+ invocation.SetContext(&PrepareInfo{
+ instance: info,
+ span: span,
+ })
+ return nil
+}
+
+func GeneralPrepareAfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ // if contains error, then record it
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(*PrepareInfo).span.Error(err.Error())
+ }
+ ctx.(*PrepareInfo).span.End()
+
+ // propagate the instance info
+ if instance, ok := results[0].(*sql.Stmt); ok && instance != nil {
+
results[0].(operator.EnhancedInstance).SetSkyWalkingDynamicField(ctx.(*PrepareInfo).instance)
+ }
+ return nil
+}
+
+type BeginTxInfo struct {
+ instance InstanceInfo
+ span tracing.Span
+}
+
+func GeneralBeginTxBeforeInvoke(invocation operator.Invocation, method string)
error {
+ span, info, err := createLocalSpan(invocation.CallerInstance(), method)
+ if err != nil || span == nil {
+ return err
+ }
+ invocation.SetContext(&BeginTxInfo{
+ instance: info,
+ span: span,
+ })
+ return nil
+}
+
+func GeneralBeginTxAfterInvoke(invocation operator.Invocation, result
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ // if contains error, then record it
+ if err, ok := result[1].(error); ok && err != nil {
+ ctx.(*BeginTxInfo).span.Error(err.Error())
+ }
+ ctx.(*BeginTxInfo).span.End()
+
+ // propagate the instance info
+ if instance, ok := result[0].(*sql.Tx); ok && instance != nil {
+
result[0].(operator.EnhancedInstance).SetSkyWalkingDynamicField(ctx.(*BeginTxInfo).instance)
+ }
+ return nil
+}
+
+func GeneralExecBeforeInvoke(invocation operator.Invocation, method string)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), method,
+ tracing.WithTag(tracing.TagDBStatement,
invocation.Args()[1].(string)))
+ if err != nil {
+ return err
+ }
+ if config.CollectParameter && len(invocation.Args()[2].([]interface{}))
> 0 {
+ span.Tag(tracing.TagDBSqlParameters,
argsToString(invocation.Args()[2].([]interface{})))
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func GeneralExecAfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
+
+func GeneralPingBeforeInvoke(invocation operator.Invocation, method string)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), method)
+ if err != nil {
+ return err
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func GeneralPingAfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[0].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
+
+func GeneralQueryBeforeInvoke(invocation operator.Invocation, method string)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), method,
+ tracing.WithTag(tracing.TagDBStatement,
invocation.Args()[1].(string)))
+ if err != nil {
+ return err
+ }
+ if config.CollectParameter && len(invocation.Args()[2].([]interface{}))
> 0 {
+ span.Tag(tracing.TagDBSqlParameters,
argsToString(invocation.Args()[2].([]interface{})))
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func GeneralQueryAfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
+
+func GeneralRawBeforeInvoke(invocation operator.Invocation, method string)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), method)
+ if err != nil {
+ return err
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func GeneralRawAfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
+
+func argsToString(args []interface{}) string {
+ switch len(args) {
+ case 0:
+ return ""
+ case 1:
+ return fmt.Sprintf("%v", args[0])
+ }
+
+ res := fmt.Sprintf("%v", args[0])
+ for _, arg := range args[1:] {
+ res += fmt.Sprintf(", %v", arg)
+ }
+ return res
+}
diff --git a/plugins/sql/entry/instance_open.go
b/plugins/sql/entry/instance_open.go
new file mode 100644
index 0000000..879269b
--- /dev/null
+++ b/plugins/sql/entry/instance_open.go
@@ -0,0 +1,58 @@
+// 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 (
+ "database/sql"
+
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+var needInfoKey = "needInfo"
+var infoKey = "info"
+
+type InstanceInterceptor struct {
+}
+
+type InstanceInfo interface {
+ Peer() string
+ ComponentID() int32
+ DBType() string
+}
+
+func (n *InstanceInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ tracing.SetRuntimeContextValue(needInfoKey, true)
+ return nil
+}
+
+func (n *InstanceInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ tracing.SetRuntimeContextValue(needInfoKey, nil)
+ info, ok := tracing.GetRuntimeContextValue(infoKey).(InstanceInfo)
+ tracing.SetRuntimeContextValue(needInfoKey, nil)
+ tracing.SetRuntimeContextValue(infoKey, nil)
+ if !ok || info == nil {
+ return nil
+ }
+
+ // adding peer address into db
+ if db, ok := results[0].(*sql.DB); ok && db != nil {
+
results[0].(operator.EnhancedInstance).SetSkyWalkingDynamicField(info)
+ }
+ return nil
+}
diff --git a/plugins/sql/entry/instrument.go b/plugins/sql/entry/instrument.go
new file mode 100644
index 0000000..4876fd1
--- /dev/null
+++ b/plugins/sql/entry/instrument.go
@@ -0,0 +1,230 @@
+// 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 (
+ "embed"
+
+ "github.com/apache/skywalking-go/plugins/core/instrument"
+)
+
+//go:embed *
+var fs embed.FS
+
+//skywalking:nocopy
+type Instrument struct {
+}
+
+func NewInstrument() *Instrument {
+ return &Instrument{}
+}
+
+func (i *Instrument) Name() string {
+ return "sql"
+}
+
+func (i *Instrument) BasePackage() string {
+ return "database/sql"
+}
+
+func (i *Instrument) VersionChecker(version string) bool {
+ return true
+}
+
+// nolint
+func (i *Instrument) Points() []*instrument.Point {
+ return []*instrument.Point{
+ {
+ PackagePath: "",
+ At: instrument.NewStructEnhance("DB"),
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewStructEnhance("Stmt"),
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewStructEnhance("Tx"),
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewStructEnhance("Conn"),
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewStaticMethodEnhance("Open",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "string"), instrument.WithArgType(1, "string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*DB"), instrument.WithResultType(1, "error")),
+ Interceptor: "InstanceInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*DB", "PingContext",
+ instrument.WithArgsCount(1),
instrument.WithArgType(0, "context.Context"),
+ instrument.WithResultCount(1),
instrument.WithResultType(0, "error")),
+ Interceptor: "PingInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*DB", "PrepareContext",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Stmt"), instrument.WithResultType(1, "error")),
+ Interceptor: "PrepareInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*DB", "ExecContext",
+ instrument.WithArgsCount(3),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "Result"), instrument.WithResultType(1, "error")),
+ Interceptor: "ExecInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*DB", "QueryContext",
+ instrument.WithArgsCount(3),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Rows"), instrument.WithResultType(1, "error")),
+ Interceptor: "QueryInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*DB", "BeginTx",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"*TxOptions"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Tx"), instrument.WithResultType(1, "error")),
+ Interceptor: "BeginTXInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*DB", "Conn",
+ instrument.WithArgsCount(1),
instrument.WithArgType(0, "context.Context"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Conn"), instrument.WithResultType(1, "error")),
+ Interceptor: "ConnInterceptor",
+ },
+ // Conn operation
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Conn", "PingContext",
+ instrument.WithArgsCount(1),
instrument.WithArgType(0, "context.Context"),
+ instrument.WithResultCount(1),
instrument.WithResultType(0, "error")),
+ Interceptor: "ConnPingInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Conn", "ExecContext",
+ instrument.WithArgsCount(3),
+ instrument.WithArgType(0, "context.Context"),
instrument.WithArgType(1, "string"),
+ instrument.WithResultCount(2),
instrument.WithArgType(0, "Result"), instrument.WithResultType(1, "error")),
+ Interceptor: "ConnExecInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Conn", "QueryContext",
+ instrument.WithArgsCount(3),
+ instrument.WithArgType(0, "context.Context"),
instrument.WithArgType(1, "string"),
+ instrument.WithResultCount(2),
instrument.WithArgType(0, "*Rows"), instrument.WithResultType(1, "error")),
+ Interceptor: "ConnQueryInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Conn",
"PrepareContext",
+ instrument.WithArgsCount(2),
+ instrument.WithArgType(0, "context.Context"),
instrument.WithArgType(1, "string"),
+ instrument.WithResultCount(2),
instrument.WithArgType(0, "*Stmt"), instrument.WithResultType(1, "error")),
+ Interceptor: "ConnPrepareInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Conn", "Raw",
+ instrument.WithArgsCount(1),
+ instrument.WithResultCount(1),
instrument.WithResultType(0, "error")),
+ Interceptor: "ConnRawInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Conn", "BeginTx",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"*TxOptions"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Tx"), instrument.WithResultType(1, "error")),
+ Interceptor: "ConnBeginTXInterceptor",
+ },
+ // TX operation
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Tx", "Commit",
+ instrument.WithArgsCount(0),
+ instrument.WithResultCount(1),
instrument.WithResultType(0, "error")),
+ Interceptor: "TxCommitInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Tx", "Rollback",
+ instrument.WithArgsCount(0),
+ instrument.WithResultCount(1),
instrument.WithResultType(0, "error")),
+ Interceptor: "TxRollbackInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Tx", "PrepareContext",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Stmt"), instrument.WithResultType(1, "error")),
+ Interceptor: "TxPrepareInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Tx", "StmtContext",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"*Stmt"),
+ instrument.WithResultCount(1),
instrument.WithResultType(0, "*Stmt")),
+ Interceptor: "TxStmtInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Tx", "ExecContext",
+ instrument.WithArgsCount(3),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "Result"), instrument.WithResultType(1, "error")),
+ Interceptor: "TxExecInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Tx", "QueryContext",
+ instrument.WithArgsCount(3),
instrument.WithArgType(0, "context.Context"), instrument.WithArgType(1,
"string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Rows"), instrument.WithResultType(1, "error")),
+ Interceptor: "TxQueryInterceptor",
+ },
+ // Stmt Operation
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Stmt", "ExecContext",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "Result"), instrument.WithResultType(1, "error")),
+ Interceptor: "StmtExecInterceptor",
+ },
+ {
+ PackagePath: "",
+ At: instrument.NewMethodEnhance("*Stmt", "QueryContext",
+ instrument.WithArgsCount(2),
instrument.WithArgType(0, "context.Context"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Rows"), instrument.WithResultType(1, "error")),
+ Interceptor: "StmtQueryInterceptor",
+ },
+ }
+}
+
+func (i *Instrument) PluginSourceCodePath() string {
+ return "entry"
+}
+
+func (i *Instrument) FS() *embed.FS {
+ return &fs
+}
diff --git a/plugins/sql/entry/span.go b/plugins/sql/entry/span.go
new file mode 100644
index 0000000..e60f194
--- /dev/null
+++ b/plugins/sql/entry/span.go
@@ -0,0 +1,59 @@
+// 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/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+func createExitSpan(caller interface{}, method string, opts
...tracing.SpanOption) (tracing.Span, error) {
+ info := getInstanceInfo(caller)
+ if info == nil {
+ return nil, nil
+ }
+
+ span, err := tracing.CreateExitSpan(info.DBType()+"/"+method,
info.Peer(), func(headerKey, headerValue string) error {
+ return nil
+ }, append(opts, tracing.WithComponent(info.ComponentID()),
+ tracing.WithLayer(tracing.SpanLayerDatabase),
+ tracing.WithTag(tracing.TagDBType, info.DBType()))...)
+ return span, err
+}
+
+func createLocalSpan(caller interface{}, method string, opts
...tracing.SpanOption) (tracing.Span, InstanceInfo, error) {
+ info := getInstanceInfo(caller)
+ if info == nil {
+ return nil, nil, nil
+ }
+
+ span, err := tracing.CreateLocalSpan(info.DBType()+"/"+method,
+ append(opts, tracing.WithComponent(info.ComponentID()),
+ tracing.WithLayer(tracing.SpanLayerDatabase),
+ tracing.WithTag(tracing.TagDBType, info.DBType()))...)
+ return span, info, err
+}
+
+func getInstanceInfo(caller interface{}) InstanceInfo {
+ instance, ok := caller.(operator.EnhancedInstance)
+ if !ok || instance == nil {
+ return nil
+ }
+ info := instance.GetSkyWalkingDynamicField().(InstanceInfo)
+ return info
+}
diff --git a/plugins/sql/entry/stmt_exec.go b/plugins/sql/entry/stmt_exec.go
new file mode 100644
index 0000000..fcb1714
--- /dev/null
+++ b/plugins/sql/entry/stmt_exec.go
@@ -0,0 +1,50 @@
+// 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/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type StmtExecInterceptor struct {
+}
+
+func (n *StmtExecInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), "Stmt/Exec")
+ if err != nil {
+ return err
+ }
+ if config.CollectParameter && len(invocation.Args()[1].([]interface{}))
> 0 {
+ span.Tag(tracing.TagDBSqlParameters,
argsToString(invocation.Args()[1].([]interface{})))
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func (n *StmtExecInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
diff --git a/plugins/sql/entry/stmt_query.go b/plugins/sql/entry/stmt_query.go
new file mode 100644
index 0000000..cec3b6e
--- /dev/null
+++ b/plugins/sql/entry/stmt_query.go
@@ -0,0 +1,50 @@
+// 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/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type StmtQueryInterceptor struct {
+}
+
+func (n *StmtQueryInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), "Stmt/Query")
+ if err != nil {
+ return err
+ }
+ if config.CollectParameter && len(invocation.Args()[1].([]interface{}))
> 0 {
+ span.Tag(tracing.TagDBSqlParameters,
argsToString(invocation.Args()[1].([]interface{})))
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func (n *StmtQueryInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/tx_commit.go
similarity index 54%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/tx_commit.go
index aabda3b..f9c76ee 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/tx_commit.go
@@ -15,21 +15,33 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
+type TxCommitInterceptor struct {
+}
+
+func (n *TxCommitInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), "Tx/Commit")
+ if err != nil {
+ return err
}
+ invocation.SetContext(span)
+ return nil
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *TxCommitInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[0].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
}
diff --git a/plugins/sql/entry/tx_exec.go b/plugins/sql/entry/tx_exec.go
new file mode 100644
index 0000000..fee5ca7
--- /dev/null
+++ b/plugins/sql/entry/tx_exec.go
@@ -0,0 +1,51 @@
+// 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/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type TxExecInterceptor struct {
+}
+
+func (n *TxExecInterceptor) BeforeInvoke(invocation operator.Invocation) error
{
+ span, err := createExitSpan(invocation.CallerInstance(), "Tx/Exec",
+ tracing.WithTag(tracing.TagDBStatement,
invocation.Args()[1].(string)))
+ if err != nil {
+ return err
+ }
+ if config.CollectParameter && len(invocation.Args()[2].([]interface{}))
> 0 {
+ span.Tag(tracing.TagDBSqlParameters,
argsToString(invocation.Args()[2].([]interface{})))
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func (n *TxExecInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/tx_prepare.go
similarity index 65%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/tx_prepare.go
index aabda3b..1e64ae8 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/tx_prepare.go
@@ -15,21 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+type TxPrepareInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *TxPrepareInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ return GeneralPrepareBeforeInvoke(invocation, "Tx/Prepare")
+}
+
+func (n *TxPrepareInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ return GeneralPrepareAfterInvoke(invocation, results...)
}
diff --git a/plugins/sql/entry/tx_query.go b/plugins/sql/entry/tx_query.go
new file mode 100644
index 0000000..0bb6336
--- /dev/null
+++ b/plugins/sql/entry/tx_query.go
@@ -0,0 +1,51 @@
+// 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/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type TxQueryInterceptor struct {
+}
+
+func (n *TxQueryInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), "Tx/Query",
+ tracing.WithTag(tracing.TagDBStatement,
invocation.Args()[1].(string)))
+ if err != nil {
+ return err
+ }
+ if config.CollectParameter && len(invocation.Args()[2].([]interface{}))
> 0 {
+ span.Tag(tracing.TagDBSqlParameters,
argsToString(invocation.Args()[2].([]interface{})))
+ }
+ invocation.SetContext(span)
+ return nil
+}
+
+func (n *TxQueryInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[1].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
+}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/tx_rollback.go
similarity index 54%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/tx_rollback.go
index aabda3b..b5cb3f8 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/tx_rollback.go
@@ -15,21 +15,33 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
+type TxRollbackInterceptor struct {
+}
+
+func (n *TxRollbackInterceptor) BeforeInvoke(invocation operator.Invocation)
error {
+ span, err := createExitSpan(invocation.CallerInstance(), "Tx/Rollback")
+ if err != nil {
+ return err
}
+ invocation.SetContext(span)
+ return nil
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *TxRollbackInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ ctx := invocation.GetContext()
+ if ctx == nil {
+ return nil
+ }
+ if err, ok := results[0].(error); ok && err != nil {
+ ctx.(tracing.Span).Error(err.Error())
+ }
+ ctx.(tracing.Span).End()
+ return nil
}
diff --git a/tools/go-agent/tools/types.go b/plugins/sql/entry/tx_stmt.go
similarity index 61%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/entry/tx_stmt.go
index aabda3b..2d898e8 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/entry/tx_stmt.go
@@ -15,21 +15,24 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package entry
-var basicDataTypes = make(map[string]bool)
+import (
+ "database/sql"
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
- }
+ "github.com/apache/skywalking-go/plugins/core/operator"
+)
+
+type TxStmtInterceptor struct {
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (n *TxStmtInterceptor) BeforeInvoke(invocation operator.Invocation) error
{
+ return nil
+}
+
+func (n *TxStmtInterceptor) AfterInvoke(invocation operator.Invocation,
results ...interface{}) error {
+ if stmt, ok := results[0].(*sql.Stmt); ok && stmt != nil {
+
results[0].(operator.EnhancedInstance).SetSkyWalkingDynamicField(getInstanceInfo(invocation.CallerInstance()))
+ }
+ return nil
}
diff --git a/plugins/sql/go.mod b/plugins/sql/go.mod
new file mode 100644
index 0000000..4732679
--- /dev/null
+++ b/plugins/sql/go.mod
@@ -0,0 +1,5 @@
+module github.com/apache/skywalking-go/plugins/sql
+
+go 1.18
+
+require github.com/go-sql-driver/mysql v1.7.1 // indirect
diff --git a/plugins/sql/mysql/instrument.go b/plugins/sql/mysql/instrument.go
new file mode 100644
index 0000000..3d60876
--- /dev/null
+++ b/plugins/sql/mysql/instrument.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 mysql
+
+import (
+ "embed"
+
+ "github.com/apache/skywalking-go/plugins/core/instrument"
+)
+
+//go:embed *
+var fs embed.FS
+
+//skywalking:nocopy
+type Instrument struct {
+}
+
+func NewInstrument() *Instrument {
+ return &Instrument{}
+}
+
+func (i *Instrument) Name() string {
+ return "sql"
+}
+
+func (i *Instrument) BasePackage() string {
+ return "github.com/go-sql-driver/mysql"
+}
+
+func (i *Instrument) VersionChecker(version string) bool {
+ return true
+}
+
+func (i *Instrument) Points() []*instrument.Point {
+ return []*instrument.Point{
+ {
+ PackagePath: "",
+ At: instrument.NewStaticMethodEnhance("ParseDSN",
+ instrument.WithArgsCount(1),
instrument.WithArgType(0, "string"),
+ instrument.WithResultCount(2),
instrument.WithResultType(0, "*Config"), instrument.WithResultType(1, "error")),
+ Interceptor: "ParseInterceptor",
+ },
+ }
+}
+
+func (i *Instrument) PluginSourceCodePath() string {
+ return "mysql"
+}
+
+func (i *Instrument) FS() *embed.FS {
+ return &fs
+}
diff --git a/tools/go-agent/tools/types.go
b/plugins/sql/mysql/parse_interceptor.go
similarity index 51%
copy from tools/go-agent/tools/types.go
copy to plugins/sql/mysql/parse_interceptor.go
index aabda3b..d6fd839 100644
--- a/tools/go-agent/tools/types.go
+++ b/plugins/sql/mysql/parse_interceptor.go
@@ -15,21 +15,41 @@
// specific language governing permissions and limitations
// under the License.
-package tools
+package mysql
-var basicDataTypes = make(map[string]bool)
+import (
+ "github.com/go-sql-driver/mysql"
-func init() {
- types := []string{
- "bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
- }
- for _, tp := range types {
- basicDataTypes[tp] = true
+ "github.com/apache/skywalking-go/plugins/core/operator"
+ "github.com/apache/skywalking-go/plugins/core/tracing"
+)
+
+type ParseInterceptor struct {
+}
+
+func (n *ParseInterceptor) BeforeInvoke(invocation operator.Invocation) error {
+ return nil
+}
+
+func (n *ParseInterceptor) AfterInvoke(invocation operator.Invocation, results
...interface{}) error {
+ if cfg, ok := results[0].(*mysql.Config); ok && cfg != nil &&
tracing.GetRuntimeContextValue("needInfo") == true {
+ tracing.SetRuntimeContextValue("info", &DBInfo{Addr: cfg.Addr})
}
+ return nil
+}
+
+type DBInfo struct {
+ Addr string
+}
+
+func (i *DBInfo) Peer() string {
+ return i.Addr
+}
+
+func (i *DBInfo) ComponentID() int32 {
+ return 5012
}
-// nolint
-func IsBasicDataType(name string) bool {
- return basicDataTypes[name]
+func (i *DBInfo) DBType() string {
+ return "Mysql"
}
diff --git a/test/plugins/scenarios/gorm/config/excepted.yml
b/test/plugins/scenarios/gorm/config/excepted.yml
index 7c044c7..bdd59d2 100644
--- a/test/plugins/scenarios/gorm/config/excepted.yml
+++ b/test/plugins/scenarios/gorm/config/excepted.yml
@@ -32,8 +32,8 @@ segmentItems:
peer: mysql-server:3306
skipAnalysis: false
tags:
- - {key: db.type, value: mysql}
- - operationName: users/create
+ - { key: db.type, value: mysql }
+ - operationName: Mysql/BeginTx
parentSpanId: 0
spanId: 2
spanLayer: Database
@@ -41,14 +41,40 @@ segmentItems:
endTime: nq 0
componentId: 5012
isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: users/create
+ parentSpanId: 0
+ spanId: 3
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql-server:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: mysql }
+ - operationName: Mysql/Tx/Commit
+ parentSpanId: 0
+ spanId: 4
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
spanType: Exit
peer: mysql-server:3306
skipAnalysis: false
tags:
- - {key: db.type, value: mysql}
+ - { key: db.type, value: Mysql }
- operationName: users/query
parentSpanId: 0
- spanId: 3
+ spanId: 5
spanLayer: Database
startTime: nq 0
endTime: nq 0
@@ -58,10 +84,10 @@ segmentItems:
peer: mysql-server:3306
skipAnalysis: false
tags:
- - {key: db.type, value: mysql}
+ - { key: db.type, value: mysql }
- operationName: users/row
parentSpanId: 0
- spanId: 4
+ spanId: 6
spanLayer: Database
startTime: nq 0
endTime: nq 0
@@ -71,10 +97,23 @@ segmentItems:
peer: mysql-server:3306
skipAnalysis: false
tags:
- - {key: db.type, value: mysql}
+ - { key: db.type, value: mysql }
+ - operationName: Mysql/BeginTx
+ parentSpanId: 0
+ spanId: 7
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
- operationName: users/update
parentSpanId: 0
- spanId: 5
+ spanId: 8
spanLayer: Database
startTime: nq 0
endTime: nq 0
@@ -84,10 +123,49 @@ segmentItems:
peer: mysql-server:3306
skipAnalysis: false
tags:
- - {key: db.type, value: mysql}
+ - { key: db.type, value: mysql }
+ - operationName: Mysql/Tx/Commit
+ parentSpanId: 0
+ spanId: 9
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql-server:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/BeginTx
+ parentSpanId: 0
+ spanId: 10
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
- operationName: users/delete
parentSpanId: 0
- spanId: 6
+ spanId: 11
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql-server:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: mysql }
+ - operationName: Mysql/Tx/Commit
+ parentSpanId: 0
+ spanId: 12
spanLayer: Database
startTime: nq 0
endTime: nq 0
@@ -97,7 +175,7 @@ segmentItems:
peer: mysql-server:3306
skipAnalysis: false
tags:
- - {key: db.type, value: mysql}
+ - { key: db.type, value: Mysql }
- operationName: GET:/execute
parentSpanId: -1
spanId: 0
@@ -110,8 +188,8 @@ segmentItems:
peer: ''
skipAnalysis: false
tags:
- - {key: http.method, value: GET}
- - {key: url, value: 'service:8080/execute'}
- - {key: status_code, value: '200'}
+ - { key: http.method, value: GET }
+ - { key: url, value: 'service:8080/execute' }
+ - { key: status_code, value: '200' }
meterItems: []
logItems: []
diff --git a/test/plugins/scenarios/mongo/plugin.yml
b/test/plugins/scenarios/mongo/plugin.yml
index 1e785b5..a57750c 100644
--- a/test/plugins/scenarios/mongo/plugin.yml
+++ b/test/plugins/scenarios/mongo/plugin.yml
@@ -22,7 +22,6 @@ export-port: 8080
support-version:
- go: 1.18
framework:
- - v1.11.0
- v1.10.5
- v1.11.1
- v1.10.6
diff --git a/test/plugins/scenarios/mongo/plugin.yml
b/test/plugins/scenarios/mysql/bin/startup.sh
old mode 100644
new mode 100755
similarity index 50%
copy from test/plugins/scenarios/mongo/plugin.yml
copy to test/plugins/scenarios/mysql/bin/startup.sh
index 1e785b5..f1f80c2
--- a/test/plugins/scenarios/mongo/plugin.yml
+++ b/test/plugins/scenarios/mysql/bin/startup.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -14,35 +16,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-entry-service: http://${HTTP_HOST}:${HTTP_PORT}/execute
-health-checker: http://${HTTP_HOST}:${HTTP_PORT}/health
-start-script: ./bin/startup.sh
-framework: go.mongodb.org/mongo-driver
-export-port: 8080
-support-version:
- - go: 1.18
- framework:
- - v1.11.0
- - v1.10.5
- - v1.11.1
- - v1.10.6
- - v1.11.2
- - v1.11.3
- - v1.11.4
- - v1.11.6
- - v1.11.7
-dependencies:
- mongo:
- image: mongo
- hostname: mongo
- expose:
- - "27017"
- environment:
- MONGO_INITDB_ROOT_USERNAME: user
- MONGO_INITDB_ROOT_PASSWORD: password
- MONGO_INITDB_DATABASE: database
- healthcheck:
- test: [ "CMD", "bash", "-c", "cat < /dev/null >
/dev/tcp/127.0.0.1/27017" ]
- interval: 5s
- timeout: 60s
- retries: 120
\ No newline at end of file
+home="$(cd "$(dirname $0)"; pwd)"
+go build ${GO_BUILD_OPTS} -o mysql main.go
+
+export SW_AGENT_PLUGIN_CONFIG_SQL_COLLECT_PARAMETER=true
+./mysql
\ No newline at end of file
diff --git a/test/plugins/scenarios/mysql/config/excepted.yml
b/test/plugins/scenarios/mysql/config/excepted.yml
new file mode 100644
index 0000000..7df8c23
--- /dev/null
+++ b/test/plugins/scenarios/mysql/config/excepted.yml
@@ -0,0 +1,250 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+segmentItems:
+ - serviceName: mysql
+ segmentSize: ge 1
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: Mysql/Ping
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/Exec
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: "DROP TABLE IF EXISTS users" }
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/Exec
+ parentSpanId: 0
+ spanId: 3
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'CREATE TABLE IF NOT EXISTS users
(id char(255), name VARCHAR(255), age INTEGER)' }
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/Exec
+ parentSpanId: 0
+ spanId: 4
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'INSERT INTO users (id, name, age)
VALUE ( ?, ?, ?)' }
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: '0, foo, 10'}
+ - operationName: Mysql/Query
+ parentSpanId: 0
+ spanId: 5
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'SELECT name FROM users WHERE id =
?' }
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: '0'}
+ - operationName: Mysql/Prepare
+ parentSpanId: 0
+ spanId: 6
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'INSERT INTO users (id, name, age)
VALUE ( ?, ?, ?)' }
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/Stmt/Exec
+ parentSpanId: 0
+ spanId: 7
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: '1, bar, 11'}
+ - operationName: Mysql/BeginTx
+ parentSpanId: 0
+ spanId: 8
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/Tx/Exec
+ parentSpanId: 0
+ spanId: 9
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'INSERT INTO users (id, name, age)
VALUE ( ?, ?, ? )' }
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: '2, foobar, 24'}
+ - operationName: Mysql/Tx/Exec
+ parentSpanId: 0
+ spanId: 10
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'UPDATE users SET name = ? WHERE
id = ?' }
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: 'foobar, 0'}
+ - operationName: Mysql/Tx/Commit
+ parentSpanId: 0
+ spanId: 11
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/BeginTx
+ parentSpanId: 0
+ spanId: 12
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Local
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: Mysql/Tx/Exec
+ parentSpanId: 0
+ spanId: 13
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'UPDATE users SET age = ? WHERE id
= ?' }
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: '48, 2'}
+ - operationName: Mysql/Tx/Exec
+ parentSpanId: 0
+ spanId: 14
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.statement, value: 'UPDATE users SET name = ? WHERE
id = ?' }
+ - { key: db.type, value: Mysql }
+ - {key: db.sql.parameters, value: 'foobar, 1'}
+ - operationName: Mysql/Tx/Rollback
+ parentSpanId: 0
+ spanId: 15
+ spanLayer: Database
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5012
+ isError: false
+ spanType: Exit
+ peer: mysql:3306
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: Mysql }
+ - operationName: GET:/execute
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 5004
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - { key: http.method, value: GET }
+ - { key: url, value: 'service:8080/execute' }
+ - { key: status_code, value: '200' }
+meterItems: []
+logItems: []
diff --git a/test/plugins/scenarios/mysql/go.mod
b/test/plugins/scenarios/mysql/go.mod
new file mode 100644
index 0000000..73340f6
--- /dev/null
+++ b/test/plugins/scenarios/mysql/go.mod
@@ -0,0 +1,5 @@
+module test/plugins/scenarios/mysql
+
+go 1.18
+
+require github.com/go-sql-driver/mysql v1.7.1 // indirect
diff --git a/test/plugins/scenarios/mysql/go.sum
b/test/plugins/scenarios/mysql/go.sum
new file mode 100644
index 0000000..fd7ae07
--- /dev/null
+++ b/test/plugins/scenarios/mysql/go.sum
@@ -0,0 +1,2 @@
+github.com/go-sql-driver/mysql v1.7.1
h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod
h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
diff --git a/test/plugins/scenarios/mysql/main.go
b/test/plugins/scenarios/mysql/main.go
new file mode 100644
index 0000000..791cb19
--- /dev/null
+++ b/test/plugins/scenarios/mysql/main.go
@@ -0,0 +1,161 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package main
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "log"
+ "net/http"
+ "time"
+
+ _ "github.com/go-sql-driver/mysql"
+
+ _ "github.com/apache/skywalking-go"
+)
+
+type testFunc func(context.Context, *sql.DB) error
+
+func main() {
+ db, err := sql.Open("mysql", "user:password@tcp(mysql:3306)/database")
+ if err != nil {
+ panic(err)
+ }
+ // See "Important settings" section.
+ db.SetConnMaxLifetime(time.Minute * 3)
+ db.SetMaxOpenConns(10)
+ db.SetMaxIdleConns(10)
+
+ route := http.NewServeMux()
+ route.HandleFunc("/execute", func(res http.ResponseWriter, req
*http.Request) {
+ tests := []struct {
+ name string
+ fn testFunc
+ }{
+ {"exec", testExec},
+ {"stmt", testStmt},
+ {"commitTx", testCommitTx},
+ {"rollbackTx", testRollbackTx},
+ }
+
+ for _, test := range tests {
+ log.Printf("excute test case %s", test.name)
+ if err1 := test.fn(req.Context(), db); err1 != nil {
+ log.Printf("test case %s failed: %v",
test.name, err1)
+ }
+ }
+ _, _ = res.Write([]byte("execute sql success"))
+ })
+
+ route.HandleFunc("/health", func(writer http.ResponseWriter, request
*http.Request) {
+ writer.Write([]byte("ok"))
+ })
+
+ log.Println("start client")
+ err = http.ListenAndServe(":8080", route)
+ if err != nil {
+ log.Fatalf("client start error: %v \n", err)
+ }
+
+}
+
+func testExec(ctx context.Context, db *sql.DB) error {
+ if err := db.PingContext(ctx); err != nil {
+ return err
+ }
+
+ if _, err := db.ExecContext(ctx, `DROP TABLE IF EXISTS users`); err !=
nil {
+ return fmt.Errorf("exec drop error: %w", err)
+ }
+
+ if _, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS users (id
char(255), name VARCHAR(255), age INTEGER)`); err != nil {
+ return fmt.Errorf("exec create error: %w", err)
+ }
+
+ // test insert
+ if _, err := db.ExecContext(ctx, `INSERT INTO users (id, name, age)
VALUE ( ?, ?, ?)`, "0", "foo", 10); err != nil {
+ return fmt.Errorf("exec insert error: %w", err)
+ }
+
+ var name string
+ // test select
+ if err := db.QueryRowContext(ctx, `SELECT name FROM users WHERE id =
?`, "0").Scan(&name); err != nil {
+ return fmt.Errorf("query select error: %w", err)
+ }
+
+ return nil
+}
+
+func testStmt(ctx context.Context, db *sql.DB) error {
+ stmt, err := db.PrepareContext(ctx, `INSERT INTO users (id, name, age)
VALUE ( ?, ?, ?)`)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ _ = stmt.Close()
+ }()
+
+ _, err = stmt.ExecContext(ctx, "1", "bar", 11)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func testCommitTx(ctx context.Context, db *sql.DB) error {
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ return fmt.Errorf("begin tx error: %v", err)
+ }
+
+ if _, err := tx.Exec(`INSERT INTO users (id, name, age) VALUE ( ?, ?, ?
)`, "2", "foobar", 24); err != nil {
+ return err
+ }
+
+ if _, err := tx.ExecContext(ctx, `UPDATE users SET name = ? WHERE id =
?`, "foobar", "0"); err != nil {
+ return err
+ }
+
+ if err := tx.Commit(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func testRollbackTx(ctx context.Context, db *sql.DB) error {
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ return fmt.Errorf("begin tx error: %v", err)
+ }
+
+ if _, err := tx.Exec(`UPDATE users SET age = ? WHERE id = ?`, 48, "2");
err != nil {
+ return err
+ }
+
+ if _, err := tx.ExecContext(ctx, `UPDATE users SET name = ? WHERE id =
?`, "foobar", "1"); err != nil {
+ return err
+ }
+
+ if err := tx.Rollback(); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/test/plugins/scenarios/mongo/plugin.yml
b/test/plugins/scenarios/mysql/plugin.yml
similarity index 67%
copy from test/plugins/scenarios/mongo/plugin.yml
copy to test/plugins/scenarios/mysql/plugin.yml
index 1e785b5..6b93abe 100644
--- a/test/plugins/scenarios/mongo/plugin.yml
+++ b/test/plugins/scenarios/mysql/plugin.yml
@@ -17,32 +17,38 @@
entry-service: http://${HTTP_HOST}:${HTTP_PORT}/execute
health-checker: http://${HTTP_HOST}:${HTTP_PORT}/health
start-script: ./bin/startup.sh
-framework: go.mongodb.org/mongo-driver
+framework: github.com/go-sql-driver/mysql
export-port: 8080
support-version:
+ - go: 1.17
+ framework:
+ - v1.7.1
- go: 1.18
framework:
- - v1.11.0
- - v1.10.5
- - v1.11.1
- - v1.10.6
- - v1.11.2
- - v1.11.3
- - v1.11.4
- - v1.11.6
- - v1.11.7
+ - v1.4.0
+ - v1.4.1
+ - v1.5.0
+ - v1.6.0
+ - v1.7.1
+ - go: 1.19
+ framework:
+ - v1.7.1
+ - go: 1.20
+ framework:
+ - v1.7.1
dependencies:
- mongo:
- image: mongo
- hostname: mongo
+ mysql:
+ image: mysql:5.7
+ hostname: mysql-server
expose:
- - "27017"
+ - "3306"
environment:
- MONGO_INITDB_ROOT_USERNAME: user
- MONGO_INITDB_ROOT_PASSWORD: password
- MONGO_INITDB_DATABASE: database
+ MYSQL_ROOT_PASSWORD: "password"
+ MYSQL_USER: "user"
+ MYSQL_PASSWORD: "password"
+ MYSQL_DATABASE: "database"
healthcheck:
- test: [ "CMD", "bash", "-c", "cat < /dev/null >
/dev/tcp/127.0.0.1/27017" ]
+ test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 60s
retries: 120
\ No newline at end of file
diff --git a/tools/go-agent/config/agent.default.yaml
b/tools/go-agent/config/agent.default.yaml
index 413fc59..6e563bd 100644
--- a/tools/go-agent/config/agent.default.yaml
+++ b/tools/go-agent/config/agent.default.yaml
@@ -59,4 +59,7 @@ plugin:
server_collect_parameters:
${SW_AGENT_PLUGIN_CONFIG_HTTP_SERVER_COLLECT_PARAMETERS:false}
mongo:
# Collect the statement of the MongoDB request
- collect_statement:
${SW_AGENT_PLUGIN_CONFIG_MONGO_COLLECT_STATEMENT:false}
\ No newline at end of file
+ collect_statement:
${SW_AGENT_PLUGIN_CONFIG_MONGO_COLLECT_STATEMENT:false}
+ sql:
+ # Collect the parameter of the SQL request
+ collect_parameter: ${SW_AGENT_PLUGIN_CONFIG_SQL_COLLECT_PARAMETER:false}
diff --git a/tools/go-agent/instrument/instrument.go
b/tools/go-agent/instrument/instrument.go
index e0b8a03..f32c298 100644
--- a/tools/go-agent/instrument/instrument.go
+++ b/tools/go-agent/instrument/instrument.go
@@ -150,11 +150,18 @@ func instrumentFiles(buildDir string, inst
api.Instrument, args []string) error
func parseFilesInArgs(args []string) (map[string]*fileInfo, error) {
parsedFiles := make(map[string]*fileInfo)
+ var lastPath string
+ defer func() {
+ if e := recover(); e != nil {
+ logrus.Errorf("panic when parsing files: %s: %v",
lastPath, e)
+ }
+ }()
for inx, path := range args {
// only process the go file
if !strings.HasSuffix(path, ".go") {
continue
}
+ lastPath = path
// parse the file
file, err := decorator.ParseFile(nil, path, nil,
parser.ParseComments)
diff --git a/tools/go-agent/instrument/plugins/register.go
b/tools/go-agent/instrument/plugins/register.go
index 0afdf5f..0089122 100644
--- a/tools/go-agent/instrument/plugins/register.go
+++ b/tools/go-agent/instrument/plugins/register.go
@@ -29,6 +29,8 @@ import (
"github.com/apache/skywalking-go/plugins/kratosv2"
"github.com/apache/skywalking-go/plugins/microv4"
"github.com/apache/skywalking-go/plugins/mongo"
+ sql_entry "github.com/apache/skywalking-go/plugins/sql/entry"
+ sql_mysql "github.com/apache/skywalking-go/plugins/sql/mysql"
)
var instruments = make([]instrument.Instrument, 0)
@@ -47,6 +49,10 @@ func init() {
// gorm related instruments
registerFramework(gorm_entry.NewInstrument())
registerFramework(gorm_mysql.NewInstrument())
+
+ // sql related instruments
+ registerFramework(sql_entry.NewInstrument())
+ registerFramework(sql_mysql.NewInstrument())
}
func registerFramework(ins instrument.Instrument) {
diff --git a/tools/go-agent/tools/enhancement.go
b/tools/go-agent/tools/enhancement.go
index 2ef0acb..927b06d 100644
--- a/tools/go-agent/tools/enhancement.go
+++ b/tools/go-agent/tools/enhancement.go
@@ -28,6 +28,7 @@ import (
const interfaceName = "interface{}"
const OtherPackageRefPrefix = "swref_"
+const parameterAppender = ", "
type ParameterInfo struct {
Name string
@@ -144,6 +145,7 @@ func (p *PackagedParameterInfo) PackagedTypeName() string {
return GenerateTypeNameByExp(p.PackagedType())
}
+// nolint
func GenerateTypeNameByExp(exp dst.Expr) string {
var data string
switch n := exp.(type) {
@@ -161,6 +163,27 @@ func GenerateTypeNameByExp(exp dst.Expr) string {
data = "[]" + GenerateTypeNameByExp(n.Elt)
case *dst.ArrayType:
data = "[]" + GenerateTypeNameByExp(n.Elt)
+ case *dst.FuncType:
+ data = "func("
+ if n.Params != nil && len(n.Params.List) > 0 {
+ for i, f := range n.Params.List {
+ if i > 0 {
+ data += parameterAppender
+ }
+ data += GenerateTypeNameByExp(f.Type)
+ }
+ }
+ data += ")"
+ if n.Results != nil && len(n.Results.List) > 0 {
+ data += "("
+ for i, f := range n.Results.List {
+ if i > 0 {
+ data += parameterAppender
+ }
+ data += GenerateTypeNameByExp(f.Type)
+ }
+ data += ")"
+ }
default:
return ""
}
diff --git a/tools/go-agent/tools/types.go b/tools/go-agent/tools/types.go
index aabda3b..8bbf785 100644
--- a/tools/go-agent/tools/types.go
+++ b/tools/go-agent/tools/types.go
@@ -22,7 +22,7 @@ var basicDataTypes = make(map[string]bool)
func init() {
types := []string{
"bool", "int8", "int16", "int32", "int64", "uint8", "uint16",
"uint32", "uint64", "int", "uint", "uintptr",
- "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte",
+ "float32", "float64", "complex64", "complex128", "string",
"error", "interface{}", "_", "byte", "any",
}
for _, tp := range types {
basicDataTypes[tp] = true