Observability API Reference
Reference for observers, middleware, OpenTelemetry, hooks, and notifications.
QueryObserver
type QueryObserver interface {
ObserveQuery(event QueryEvent)
}
Attach observers with WithQueryObserver:
type MetricsObserver struct{}
func (m *MetricsObserver) ObserveQuery(event quark.QueryEvent) {
metrics.Record(event.Table, event.Operation, event.Duration, event.Rows, event.Error)
}
client, err := quark.New("postgres", dsn,
quark.WithQueryObserver(&MetricsObserver{}),
)
QueryEvent
type QueryEvent struct {
SQL string
Args []any
Duration time.Duration
Rows int64
Error error
Table string
Operation string
}
Operations include values such as SELECT, EXEC, QUERY_ROW,
SELECT (stream), SELECT (cursor), RAW_QUERY, and RAW_EXEC.
Middleware
type Middleware interface {
WrapExec(next ExecFunc) ExecFunc
WrapQuery(next QueryFunc) QueryFunc
WrapQueryRow(next QueryRowFunc) QueryRowFunc
}
Function types:
type ExecFunc func(ctx context.Context, exec Executor, sqlStr string, args []any) (sql.Result, error)
type QueryFunc func(ctx context.Context, exec Executor, sqlStr string, args []any) (*sql.Rows, error)
type QueryRowFunc func(ctx context.Context, exec Executor, sqlStr string, args []any) *sql.Row
Embed BaseMiddleware to override only the paths you need:
type LoggingMiddleware struct {
quark.BaseMiddleware
}
func (l *LoggingMiddleware) WrapQuery(next quark.QueryFunc) quark.QueryFunc {
return func(ctx context.Context, exec quark.Executor, sqlStr string, args []any) (*sql.Rows, error) {
start := time.Now()
rows, err := next(ctx, exec, sqlStr, args)
log.Printf("query duration=%s err=%v sql=%s", time.Since(start), err, sqlStr)
return rows, err
}
}
OpenTelemetry
import quarkotel "github.com/jcsvwinston/quark/otel"
client, err := quark.New("postgres", dsn,
quark.WithMiddleware(quarkotel.New()),
)
The middleware creates spans:
| Execution | Span |
|---|---|
ExecContext | quark.exec |
QueryContext | quark.query |
QueryRowContext | quark.query_row |
Attributes include db.statement and db.operation.
Hooks
Entity-level hooks:
type BeforeCreateHook interface {
BeforeCreate(ctx context.Context) error
}
Available hook interfaces:
| Interface | Method |
|---|---|
BeforeCreateHook | BeforeCreate(context.Context) error |
AfterCreateHook | AfterCreate(context.Context) error |
BeforeUpdateHook | BeforeUpdate(context.Context) error |
AfterUpdateHook | AfterUpdate(context.Context) error |
BeforeDeleteHook | BeforeDelete(context.Context) error |
AfterDeleteHook | AfterDelete(context.Context) error |
Notifications
Notify(ctx context.Context, provider ClientProvider, channel, payload string) error
Sends a database notification where supported.
err := quark.Notify(ctx, client, "user_events", `{"type":"signup","id":123}`)
Current support:
| Dialect | Behavior |
|---|---|
| PostgreSQL | Uses pg_notify($1, $2). |
| MySQL | Returns not supported. |
| SQLite | Returns not supported. |
| Other dialects | Returns not supported. |
NewEventBus(client *Client) *EventBus
Creates an experimental event bus wrapper. CreateListener is not implemented
in the current release and returns ErrDialectNotSupported.