A SQL wrapper including Zipkin instrumentation
import (
_ "github.com/go-sql-driver/mysql"
zipkinsql "github.com/openzipkin-contrib/zipkin-go-sql"
zipkin "github.com/openzipkin/zipkin-go"
)
var (
driverName string
err error
db *sql.DB
tracer *zipkin.Tracer
)
// Register our zipkinsql wrapper for the provided MySQL driver.
driverName, err = zipkinsql.Register("mysql", tracer, zipkinsql.WithAllTraceOptions())
if err != nil {
log.Fatalf("unable to register zipkin driver: %v\n", err)
}
// Connect to a MySQL database using the zipkinsql driver wrapper.
db, err = sql.Open(driverName, "mysql://user:[email protected]:3306/db")You can also wrap your own driver with zipkin instrumentation as follows:
import (
mysql "github.com/go-sql-driver/mysql"
zipkinsql "github.com/openzipkin-contrib/zipkin-go-sql"
zipkinmodel "github.com/openzipkin/zipkin-go/model"
)
var (
driver driver.Driver
err error
db *sql.DB
tracer *zipkin.Tracer
)
// Explicitly wrap the MySQL driver with zipkinsql
driver = zipkinsql.Wrap(
&mysql.MySQLDriver{},
tracer,
zipkinsql.WithRemoteEndpoint(zipkinmodel.Endpoint{
ServiceName: "resultsdb",
Port: 5432
}),
)
// Register our zipkinsql wrapper as a database driver
sql.Register("zipkinsql-mysql", driver)
// Connect to a MySQL database using the zipkinsql driver wrapper
db, err = sql.Open("zipkinsql-mysql", "mysql://user:[email protected]:3306/db")Projects providing their own abstractions on top of database/sql/driver can also wrap an existing driver.Conn interface directly with zipkinsql.
import zipkinsql "github.com/openzipkin-contrib/zipkin-go-sql"
func initializeConn(...) driver.Conn {
// create custom driver.Conn
conn := Connect(...)
// wrap with zipkinsql
return zipkinsql.WrapConn(conn, tracer, zipkinsql.WithAllTraceOptions())
}Go 1.10+ provides a new driver.Connector interface that can be wrapped directly by zipkinsql without the need for zipkinsql to register a driver.Driver.
Example:
import(
zipkinsql "github.com/openzipkin-contrib/zipkin-go-sql"
"github.com/lib/pq"
)
var (
connector driver.Connector
err error
db *sql.DB
tracer *zipkin.Tracer
)
connector, err = pq.NewConnector("postgres://user:pass@host:5432/db")
if err != nil {
log.Fatalf("unable to create postgres connector: %v\n", err)
}
// Wrap the driver.Connector with zipkinsql.
connector = zipkinsql.WrapConnector(connector, tracer, zipkinsql.WithAllTraceOptions())
// Use the wrapped driver.Connector.
db = sql.OpenDB(connector)If using the sqlx library with named queries you will need to use the
sqlx.NewDb function to wrap an existing *sql.DB connection. sqlx.Open and sqlx.Connect methods won't work.
First create a *sql.DB connection and then create a *sqlx.DB connection by wrapping the former and keeping the same driver name e.g.:
driverName, err := zipkinsql.Register("postgres", zipkinsql.WithAllTraceOptions())
if err != nil { ... }
db, err := sql.Open(driverName, "postgres://localhost:5432/my_database")
if err != nil { ... }
// Keep the driver name!
dbx := sqlx.NewDb(db, "postgres")Instrumentation is possible if the context is being passed downstream in methods.
This is not only for instrumentation purposes but also a good practice in go programming. database/sql package exposes already a set of methods that receive the context as first paramenter:
*DB.Begin->*DB.BeginTx*DB.Exec->*DB.ExecContext*DB.Ping->*DB.PingContext*DB.Prepare->*DB.PrepareContext*DB.Query->*DB.QueryContext*DB.QueryRow->*DB.QueryRowContext*Stmt.Exec->*Stmt.ExecContext*Stmt.Query->*Stmt.QueryContext*Stmt.QueryRow->*Stmt.QueryRowContext*Tx.Exec->*Tx.ExecContext*Tx.Prepare->*Tx.PrepareContext*Tx.Query->*Tx.QueryContext*Tx.QueryRow->*Tx.QueryRowContext