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