Skip to content

openzipkin-contrib/zipkin-go-sql

Repository files navigation

Zipkin instrumentation SQL

Build Status Go Report Card GoDoc

A SQL wrapper including Zipkin instrumentation

Usage

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)

Using jmoiron/sqlx

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")

Usage of *Context methods

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