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 850a4cb feat: add tracing.TagDBStatement and tracing.TagDBSqlParameters for gorm (#189) 850a4cb is described below commit 850a4cb4133538da23c0cfc9e806f268a2a6f68a Author: Hair1ossTeenager <45008570+hair1ossteena...@users.noreply.github.com> AuthorDate: Wed Jul 31 18:21:49 2024 +0800 feat: add tracing.TagDBStatement and tracing.TagDBSqlParameters for gorm (#189) --- CHANGES.md | 1 + plugins/gorm/entry/callback.go | 19 +++++++++++++++++++ plugins/gorm/entry/config.go | 23 +++++++++++++++++++++++ plugins/gorm/entry/interceptor_test.go | 17 ++++++++++++++++- test/plugins/scenarios/gorm/bin/startup.sh | 2 ++ test/plugins/scenarios/gorm/config/excepted.yml | 10 ++++++++++ tools/go-agent/config/agent.default.yaml | 3 +++ 7 files changed, 74 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 26f08f9..e7080b9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Release Notes. * Support higher versions of grpc. * Support [go-elasticsearchv8](https://github.com/elastic/go-elasticsearch) database client framework. * Support `http.Hijacker` interface for mux plugin. +* Support collect statements and parameters in the Gorm plugin. ### Bug Fixes * Fix panic error when root span finished. diff --git a/plugins/gorm/entry/callback.go b/plugins/gorm/entry/callback.go index 5aa2b2b..51b6686 100644 --- a/plugins/gorm/entry/callback.go +++ b/plugins/gorm/entry/callback.go @@ -57,8 +57,27 @@ func afterCallback(dbInfo DatabaseInfo) func(db *gorm.DB) { defer span.End() + span.Tag(tracing.TagDBStatement, db.Statement.SQL.String()) + if config.CollectParameter && len(db.Statement.Vars) > 0 { + span.Tag(tracing.TagDBSqlParameters, argsToString(db.Statement.Vars)) + } if db.Statement.Error != nil { span.Error(db.Statement.Error.Error()) } } } + +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/gorm/entry/config.go b/plugins/gorm/entry/config.go new file mode 100644 index 0000000..bd2c2dd --- /dev/null +++ b/plugins/gorm/entry/config.go @@ -0,0 +1,23 @@ +// 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 + +//skywalking:config gorm +var config struct { + CollectParameter bool `config:"collect_parameter"` +} diff --git a/plugins/gorm/entry/interceptor_test.go b/plugins/gorm/entry/interceptor_test.go index 9321b5f..76600ca 100644 --- a/plugins/gorm/entry/interceptor_test.go +++ b/plugins/gorm/entry/interceptor_test.go @@ -25,6 +25,7 @@ import ( "time" "github.com/apache/skywalking-go/plugins/core" + "github.com/apache/skywalking-go/plugins/core/tracing" "github.com/apache/skywalking-go/plugins/gorm/mysql" "github.com/stretchr/testify/assert" @@ -51,7 +52,11 @@ func TestInterceptor(t *testing.T) { err = interceptor.AfterInvoke(nil, db, err) assert.Nil(t, err, "failed to invoke AfterInvoke") - res := db.Exec("select * from test") + config.CollectParameter = true + id := "1" + name := "test" + sqlString := "select * from test where id = ? and name = ?" + res := db.Exec(sqlString, id, name) assert.Equal(t, errConnectionExecute, res.Error, "failed to invoke Rows") time.Sleep(100 * time.Millisecond) @@ -64,6 +69,16 @@ func TestInterceptor(t *testing.T) { assert.Nil(t, spans[0].Refs(), "refs should be nil") assert.Greater(t, spans[0].StartTime(), int64(0), "end time should be greater than zero") assert.Greater(t, spans[0].EndTime(), int64(0), "end time should be greater than zero") + tagsKV := map[string]string{ + tracing.TagDBType: "mysql", + tracing.TagDBStatement: sqlString, + tracing.TagDBSqlParameters: fmt.Sprintf("%s, %s", id, name), + } + for _, tag := range spans[0].Tags() { + if v, ok := tagsKV[tag.Key]; ok { + assert.Equal(t, v, tag.Value, fmt.Sprintf("%s should be %s, not %s", tag.Key, v, tag.Value)) + } + } } type TestDialector struct { diff --git a/test/plugins/scenarios/gorm/bin/startup.sh b/test/plugins/scenarios/gorm/bin/startup.sh index fffd7b4..ad57f6d 100755 --- a/test/plugins/scenarios/gorm/bin/startup.sh +++ b/test/plugins/scenarios/gorm/bin/startup.sh @@ -19,4 +19,6 @@ home="$(cd "$(dirname $0)"; pwd)" go build ${GO_BUILD_OPTS} -o gorm +export SW_AGENT_PLUGIN_CONFIG_GORM_COLLECT_PARAMETER=true + ./gorm \ No newline at end of file diff --git a/test/plugins/scenarios/gorm/config/excepted.yml b/test/plugins/scenarios/gorm/config/excepted.yml index bdd59d2..2fb524e 100644 --- a/test/plugins/scenarios/gorm/config/excepted.yml +++ b/test/plugins/scenarios/gorm/config/excepted.yml @@ -33,6 +33,7 @@ segmentItems: skipAnalysis: false tags: - { key: db.type, value: mysql } + - { key: db.statement, value: 'CREATE TABLE IF NOT EXISTS users (id char(255), name VARCHAR(255), age INTEGER)' } - operationName: Mysql/BeginTx parentSpanId: 0 spanId: 2 @@ -59,6 +60,8 @@ segmentItems: skipAnalysis: false tags: - { key: db.type, value: mysql } + - { key: db.statement, value: 'INSERT INTO `users` (`name`,`age`) VALUES (?,?)' } + - { key: db.sql.parameters, value: 'Jinzhu, 18' } - operationName: Mysql/Tx/Commit parentSpanId: 0 spanId: 4 @@ -85,6 +88,7 @@ segmentItems: skipAnalysis: false tags: - { key: db.type, value: mysql } + - { key: db.statement, value: 'SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1' } - operationName: users/row parentSpanId: 0 spanId: 6 @@ -98,6 +102,8 @@ segmentItems: skipAnalysis: false tags: - { key: db.type, value: mysql } + - { key: db.statement, value: 'SELECT name,age FROM `users` WHERE name = ?' } + - { key: db.sql.parameters, value: 'jinzhu' } - operationName: Mysql/BeginTx parentSpanId: 0 spanId: 7 @@ -124,6 +130,8 @@ segmentItems: skipAnalysis: false tags: - { key: db.type, value: mysql } + - { key: db.statement, value: 'UPDATE `users` SET `name`=? WHERE name = ?' } + - { key: db.sql.parameters, value: 'hello, jinzhu' } - operationName: Mysql/Tx/Commit parentSpanId: 0 spanId: 9 @@ -163,6 +171,8 @@ segmentItems: skipAnalysis: false tags: - { key: db.type, value: mysql } + - { key: db.statement, value: 'DELETE FROM `users` WHERE `users`.`id` = ?' } + - { key: db.sql.parameters, value: '1' } - operationName: Mysql/Tx/Commit parentSpanId: 0 spanId: 12 diff --git a/tools/go-agent/config/agent.default.yaml b/tools/go-agent/config/agent.default.yaml index 38c1cdf..c7e3f81 100644 --- a/tools/go-agent/config/agent.default.yaml +++ b/tools/go-agent/config/agent.default.yaml @@ -97,6 +97,9 @@ plugin: mongo: # Collect the statement of the MongoDB request collect_statement: ${SW_AGENT_PLUGIN_CONFIG_MONGO_COLLECT_STATEMENT:false} + gorm: + # Collect the parameter of the gorm SQL request + collect_parameter: ${SW_AGENT_PLUGIN_CONFIG_GORM_COLLECT_PARAMETER:false} sql: # Collect the parameter of the SQL request collect_parameter: ${SW_AGENT_PLUGIN_CONFIG_SQL_COLLECT_PARAMETER:false}