Skip to content

Commit

Permalink
SQL Driver instrumentation: Database auto detection (#446)
Browse files Browse the repository at this point in the history
* SQL driver instrumentation: autodetect for

* MySQL
* Postgres
* Redis

`startSQLSpan` now returns db specific error key
  • Loading branch information
willianpc authored Sep 26, 2023
1 parent 3ef5096 commit bdfda2b
Show file tree
Hide file tree
Showing 21 changed files with 725 additions and 73 deletions.
10 changes: 5 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,20 @@ workflows:
- build:
name: "go1.17"
image: "cimg/go:1.17"
exclude_dirs: "./internal/bin/sql ./example/gin"
exclude_dirs: "./internal/bin/sql ./example/gin ./example/sql-redis"
- build:
name: "go1.16"
image: "cimg/go:1.16"
exclude_dirs: "./internal/bin/sql ./example/gin ./example/grpc-client-server ./instrumentation/instafiber"
exclude_dirs: "./internal/bin/sql ./example/gin ./example/sql-redis ./example/grpc-client-server ./instrumentation/instafiber"
- build:
name: "go1.15"
image: "cimg/go:1.15"
exclude_dirs: "./instrumentation/instaredigo ./internal/bin/sql ./example/gin ./instrumentation/instagorm ./example/grpc-client-server ./instrumentation/instafiber"
exclude_dirs: "./instrumentation/instaredigo ./internal/bin/sql ./example/gin ./example/sql-redis ./instrumentation/instagorm ./example/grpc-client-server ./instrumentation/instafiber"
- build:
name: "go1.14"
image: "cimg/go:1.14"
exclude_dirs: "./instrumentation/instaecho ./instrumentation/instaredigo ./internal/bin/sql ./instrumentation/cloud.google.com/go ./example/gin ./instrumentation/instagorm ./example/grpc-client-server ./instrumentation/instafiber ./instrumentation/instaawsv2"
exclude_dirs: "./instrumentation/instaecho ./instrumentation/instaredigo ./internal/bin/sql ./instrumentation/cloud.google.com/go ./example/gin ./instrumentation/instagorm ./example/grpc-client-server ./instrumentation/instafiber ./instrumentation/instaawsv2 ./example/sql-redis"
- build:
name: "go1.13"
image: "cimg/go:1.13"
exclude_dirs: "./instrumentation/instaecho ./instrumentation/instaredigo ./internal/bin/sql ./instrumentation/cloud.google.com/go ./example/gin ./instrumentation/instagorm ./example/grpc-client-server ./instrumentation/instafiber ./instrumentation/instaawsv2"
exclude_dirs: "./instrumentation/instaecho ./instrumentation/instaredigo ./internal/bin/sql ./instrumentation/cloud.google.com/go ./example/gin ./instrumentation/instagorm ./example/grpc-client-server ./instrumentation/instafiber ./instrumentation/instaawsv2 ./example/sql-redis"
18 changes: 18 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,21 @@ services:
ports:
- 5671:5671
- 5672:5672

redis:
image: redis
ports:
- 6379:6379
command: ["redis-server", "--requirepass", "redispw"]

mysql:
image: mysql:8.0.1
platform: linux/amd64
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: gopw
MYSQL_DATABASE: godb
MYSQL_USER: go
MYSQL_PASSWORD: gopw
MYSQL_ROOT_HOST: 0.0.0.0
24 changes: 21 additions & 3 deletions example/http-database-greeter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,29 @@ var (
}
)

func agentReady() chan bool {
ch := make(chan bool)

go func() {
for {
if instana.Ready() {
ch <- true
}
}
}()

return ch
}

// How to run the test:
// 1. Make sure the agent is running, so you can see traces in the dashboard
// 2. Start Postgres from the root folder running docker-compose up postgres
// 3. Run the app with go run . -l 0.0.0.0:9090 -db="postgres://postgres:mysecretpassword@localhost:5432/postgres?sslmode=disable"
// 4. Test the app by calling http://localhost:9090/John

func main() {
flag.StringVar(&args.DBConnStr, "db", os.Getenv("POSTGRES"), "PostgreSQL connection string")
flag.StringVar(&args.ListenAddr, "l", os.Getenv("LISTEN_ADDR"), "Server listen address")
flag.StringVar(&args.DBConnStr, "db", "postgres://postgres:mysecretpassword@localhost:5432/postgres?sslmode=disable", "PostgreSQL connection string")
flag.StringVar(&args.ListenAddr, "l", "localhost:9090", "Server listen address")
flag.Parse()

if args.DBConnStr == "" || args.ListenAddr == "" {
Expand All @@ -46,7 +60,11 @@ func main() {

// First we create an instance of instana.Sensor, a container that will be used to inject
// tracer into all instrumented methods.
sensor := instana.NewSensor("greeter-server")
sensor := instana.InitCollector(&instana.Options{
Service: "greeter-server",
})

<-agentReady()

// Create a new DB connection using instana.SQLOpen(). This is a drop-in replacement for
// database/sql.Open() that makes sure that the instrumented version of a driver is used.
Expand Down
15 changes: 15 additions & 0 deletions example/sql-mysql/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module sql-mysql.com

go 1.18

require (
github.com/go-sql-driver/mysql v1.7.1
github.com/instana/go-sensor v1.55.2
)

require (
github.com/looplab/fsm v1.0.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
)

replace github.com/instana/go-sensor => ../..
23 changes: 23 additions & 0 deletions example/sql-mysql/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/looplab/fsm v1.0.1 h1:OEW0ORrIx095N/6lgoGkFkotqH6s7vaFPsgjLAaF5QU=
github.com/looplab/fsm v1.0.1/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
63 changes: 63 additions & 0 deletions example/sql-mysql/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// (c) Copyright IBM Corp. 2023

package main

import (
"io"
"net/http"

_ "github.com/go-sql-driver/mysql"
instana "github.com/instana/go-sensor"
)

var s instana.TracerLogger

func init() {
s = instana.InitCollector(&instana.Options{
Service: "MySQL app",
})
}

func agentReady() chan bool {
ch := make(chan bool)

go func() {
for {
if instana.Ready() {
ch <- true
}
}
}()

return ch
}

func handler(w http.ResponseWriter, req *http.Request) {
db, err := instana.SQLInstrumentAndOpen(s, "mysql", "go:gopw@tcp(localhost:3306)/godb")
// db, err := instana.SQLInstrumentAndOpen(s, "mysql", "go:gopw@/godb")
if err != nil {
panic(err)
}

r, err := db.QueryContext(req.Context(), "SELECT 'Current date is' || CURDATE();")

if err != nil {
panic(err)
}

var buf, res string

for r.Next() {
r.Scan(&buf)
res += " " + buf
}

io.WriteString(w, res+" - hello\n")

}

func main() {
<-agentReady()
http.HandleFunc("/mysql", instana.TracingHandlerFunc(s, "/mysql", handler))
http.ListenAndServe(":9090", nil)
}
18 changes: 18 additions & 0 deletions example/sql-redis/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module sql-go-redis.com

go 1.18

require (
github.com/bonede/go-redis-driver v0.1.0
github.com/instana/go-sensor v1.55.2
)

require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/looplab/fsm v1.0.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/redis/go-redis/v9 v9.0.5 // indirect
)

replace github.com/instana/go-sensor => ../../
31 changes: 31 additions & 0 deletions example/sql-redis/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
github.com/bonede/go-redis-driver v0.1.0 h1:4m+eaXPjUULTfB6Y2sWBSZe/sXzGDdx2nWVhQhUEB54=
github.com/bonede/go-redis-driver v0.1.0/go.mod h1:aBnTYUPmFw6wbAmmMHQOyUuuXnFS0p6AxJw7o5Jt03Q=
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/looplab/fsm v1.0.1 h1:OEW0ORrIx095N/6lgoGkFkotqH6s7vaFPsgjLAaF5QU=
github.com/looplab/fsm v1.0.1/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
80 changes: 80 additions & 0 deletions example/sql-redis/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// (c) Copyright IBM Corp. 2023

package main

import (
"context"
"fmt"
"io"
"net/http"
"time"

instana "github.com/instana/go-sensor"

_ "github.com/bonede/go-redis-driver"
)

func agentReady() chan bool {
ch := make(chan bool)

go func() {
for {
time.Sleep(time.Millisecond * 5)
if instana.Ready() {
ch <- true
}
}
}()

return ch
}

func nameFromRedis(ctx context.Context, s instana.TracerLogger) string {
db, err := instana.SQLInstrumentAndOpen(s, "redis", ":redispw@localhost:6379")
// db, err := instana.SQLInstrumentAndOpen(s, "redis", "localhost:6379")

if err != nil {
panic("instrument error:" + err.Error())
}
defer db.Close()

_, err = db.ExecContext(ctx, "SET name Instana EX 5")
if err != nil {
panic("ExecContext error:" + err.Error())
}

rows, err := db.QueryContext(ctx, "GET name")

if err != nil {
fmt.Println("error on query context")
}

if err = rows.Err(); err != nil {
panic(err)
}
defer rows.Close()

if ok := rows.Next(); ok {
var res string
rows.Scan(&res)
return res
}

return ""
}

func main() {
s := instana.InitCollector(&instana.Options{
Service: "Redis with SQL instrumentation",
})

<-agentReady()
fmt.Println("agent connected")

http.HandleFunc("/redis", instana.TracingHandlerFunc(s, "/redis", func(w http.ResponseWriter, r *http.Request) {
name := nameFromRedis(r.Context(), s)
io.WriteString(w, name+"\n")
}))

http.ListenAndServe(":9090", nil)
}
Loading

0 comments on commit bdfda2b

Please sign in to comment.