Re: ngrok/sqlmw: an abstraction for database/sql interceptors and middleware

169 views
Skip to first unread message

Alan Shreve

unread,
Jan 16, 2020, 12:06:22 PM1/16/20
to Alan Shreve, golang-nuts
And of course I forgot to include a link to the code as well. Sorry for all the messages.


On Thu, Jan 16, 2020 at 5:19 AM Alan Shreve <al...@inconshreveable.com> wrote:
Forgot to paste in an example, see below:

func run(dsn string) {
        // install the wrapped driver
        sql.Register("postgres-mw", sqlmw.Driver(pq.Dirver{}, new(sqlInterceptor)))
        db, err := sql.Open("postgres-mw", dsn)
        ...
}

type sqlInterceptor struct {
        sqlmw.NullInterceptor
}

func (in *sqlInterceptor) StmtQueryContext(ctx context.Context, conn driver.StmtQueryContext, query string, args []driver.NamedValue) (driver.Rows, error) {
        startedAt := time.Now()
        rows, err := conn.QueryContext(ctx, args)
        log.Debug("executed sql query", "duration", time.Since(startedAt), "query", query, "args", args, "err", err)
        return rows, err
}

On Thu, Jan 16, 2020 at 5:16 AM Alan Shreve <al...@inconshreveable.com> wrote:
Hi golang-nuts -

This is an abstraction that we needed at ngrok. It allows you to intermediate calls to a database/sql Driver just like a client-side grpc interceptor would. This makes it an excellent abstraction layer upon which to build instrumentation and other middleware-like functionality.

There are a number of similar projects which provided instrumentation for logging/tracing and a few others that were aimed solely at providing callbacks for instrumentation, but I realized a more general-purpose abstraction would provide more power to the programmer by providing the ability to intercept and modify calls and return values.

Hope it's helpful to others. Feedback appreciated.

Alan Shreve

unread,
Jan 16, 2020, 12:06:24 PM1/16/20
to golang-nuts

Alan Shreve

unread,
Jan 16, 2020, 12:08:03 PM1/16/20
to Alan Shreve, golang-nuts
Forgot to paste in an example, see below:

func run(dsn string) {
        // install the wrapped driver
        sql.Register("postgres-mw", sqlmw.Driver(pq.Dirver{}, new(sqlInterceptor)))
        db, err := sql.Open("postgres-mw", dsn)
        ...
}

type sqlInterceptor struct {
        sqlmw.NullInterceptor
}

func (in *sqlInterceptor) StmtQueryContext(ctx context.Context, conn driver.StmtQueryContext, query string, args []driver.NamedValue) (driver.Rows, error) {
        startedAt := time.Now()
        rows, err := conn.QueryContext(ctx, args)
        log.Debug("executed sql query", "duration", time.Since(startedAt), "query", query, "args", args, "err", err)
        return rows, err
}

On Thu, Jan 16, 2020 at 5:16 AM Alan Shreve <al...@inconshreveable.com> wrote:
Reply all
Reply to author
Forward
0 new messages