sqlcommenter

A Golang implementation of SQLCommenter.

With sqlcommenter, you can add key-value attributes to a context, and those attributes will be added to your outgoing SQL queries in the SQLComment-standardized format:

ctx = sqlcommenter.NewContext(ctx, "endpoint", "ListWidgets")
// ...
db.QueryContext(ctx, "select * from widgets")

The above code would send the following SQL to your database:

select * from widgets /*endpoint='ListWidgets'*/

For the common case that you want to add your OpenTelemetry traces to logs, you can just write:

ctx = otelsqlcommenter.NewContext(ctx)
// ...
db.QueryContext(ctx, "select * from widgets")

Which would produce the de facto standardized fields traceparent and tracestate:

select * from widgets /*traceparent='00-5bd66ef5095369c7b0d1f8f4bd33716a-c532cb4098ac3dd2-01',tracestate='congo%3Dt61rcWkgMzE%2Crojo%3D00f067aa0ba902b7'*/

Installation

go get github.com/ucarion/sqlcommenter

Usage

Adding SQLCommenter attributes

To add a key-value attribute pair to your SQL commands, use NewContext from this package. You can pass multiple key-value pairs in a single call:

ctx = sqlcommenter.NewContext(ctx, "key1", "value1", "key2", "value2")

And then make sure to pass that same ctx to your database operations (i.e. calls to QueryContext, ExecContext, PrepareContext, etc.).

Adding OpenTelemetry-based SQLCommenter attributes

The subpackage otelsqlcommenter from this module populates the attributes traceparent and tracestate from the current span context (i.e. trace.SpanContextFromContext). You can use this to quickly hook up OpenTelemetry to your SQL logs:

ctx = otelsqlcommenter.NewContext(ctx)

This functionality is in its own package, so if you don’t use otelsqlcommenter then no OpenTelemetry code is included in your build.

Migrating to sqlcommenter

sqlcommenter is implemented as a database driver that wraps on top of your existing database driver. This section details how you can create and use a sqlcommenter database driver.

Typical use of the database/sql package looks something like:

db, err := sql.Open("xxx", "...")
// ...
rows, err := db.QueryContext(ctx, "select 1 + 1")

To move over to sqlcommenter, you’ll first need to register the sqlcommenter driver, and then call sql.Open with that driver instead. The Driver function from this package provides that driver, but it requires an underlying database/sql/driver.Driver to wrap on top of. You will need to identify what your underlying driver is.

For the most commonly-used database packages, the drivers are:

If you’re not using one of the packages above, then look for where you’re calling sql.Open("xxx", ...) in your code. Then look for a call to sql.Register("xxx", yyy) in your database driver package. yyy will be the driver you need to wrap.

Once you have a driver in hand, then replace:

db, err := sql.Open("xxx", "...")

With:

// mydriver is the driver you identified from before, e.g. &mysql.MySQLDriver{}
sql.Register("sqlcommenter-xxx", sqlcommenter.Driver(mydriver))
db, err := sql.Open("sqlcommenter-xxx", "...")

No other changes are required. Because sqlcommenter will not modify queries if there are no attributes set, this operation will be a no-op. But now if you do:

ctx = sqlcommenter.NewContext("foo", "bar")
rows, err := db.QueryContext(ctx, "select 1 + 1")

You can check your database logs, and see that you actually queried:

select 1 + 1 /*foo='bar'*/

GitHub

View Github