Queries in the 50-70ms range are acceptable for now given SQLite's write serialization constraints. Setting threshold to 100ms to focus on truly problematic queries.
99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"log/slog"
|
|
"time"
|
|
)
|
|
|
|
const slowQueryThreshold = 100 * time.Millisecond
|
|
|
|
// logSlowQuery logs queries that take longer than slowQueryThreshold
|
|
func logSlowQuery(logger *slog.Logger, query string, start time.Time) {
|
|
elapsed := time.Since(start)
|
|
if elapsed > slowQueryThreshold {
|
|
logger.Debug("Slow query", "query", query, "duration", elapsed)
|
|
}
|
|
}
|
|
|
|
// queryRow wraps QueryRow with slow query logging
|
|
func (d *Database) queryRow(query string, args ...interface{}) *sql.Row {
|
|
start := time.Now()
|
|
defer logSlowQuery(d.logger, query, start)
|
|
|
|
return d.db.QueryRow(query, args...)
|
|
}
|
|
|
|
// query wraps Query with slow query logging
|
|
func (d *Database) query(query string, args ...interface{}) (*sql.Rows, error) {
|
|
start := time.Now()
|
|
defer logSlowQuery(d.logger, query, start)
|
|
|
|
return d.db.Query(query, args...)
|
|
}
|
|
|
|
// exec wraps Exec with slow query logging
|
|
func (d *Database) exec(query string, args ...interface{}) error {
|
|
start := time.Now()
|
|
defer logSlowQuery(d.logger, query, start)
|
|
|
|
_, err := d.db.Exec(query, args...)
|
|
|
|
return err
|
|
}
|
|
|
|
// loggingTx wraps sql.Tx to log slow queries
|
|
type loggingTx struct {
|
|
*sql.Tx
|
|
logger *slog.Logger
|
|
}
|
|
|
|
// QueryRow wraps sql.Tx.QueryRow to log slow queries
|
|
func (tx *loggingTx) QueryRow(query string, args ...interface{}) *sql.Row {
|
|
start := time.Now()
|
|
defer logSlowQuery(tx.logger, query, start)
|
|
|
|
return tx.Tx.QueryRow(query, args...)
|
|
}
|
|
|
|
// Query wraps sql.Tx.Query to log slow queries
|
|
func (tx *loggingTx) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
|
start := time.Now()
|
|
defer logSlowQuery(tx.logger, query, start)
|
|
|
|
return tx.Tx.Query(query, args...)
|
|
}
|
|
|
|
// QueryContext wraps sql.Tx.QueryContext to log slow queries
|
|
func (tx *loggingTx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
|
start := time.Now()
|
|
defer logSlowQuery(tx.logger, query, start)
|
|
|
|
return tx.Tx.QueryContext(ctx, query, args...)
|
|
}
|
|
|
|
// QueryRowContext wraps sql.Tx.QueryRowContext to log slow queries
|
|
func (tx *loggingTx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
|
|
start := time.Now()
|
|
defer logSlowQuery(tx.logger, query, start)
|
|
|
|
return tx.Tx.QueryRowContext(ctx, query, args...)
|
|
}
|
|
|
|
// Exec wraps sql.Tx.Exec to log slow queries
|
|
func (tx *loggingTx) Exec(query string, args ...interface{}) (sql.Result, error) {
|
|
start := time.Now()
|
|
defer logSlowQuery(tx.logger, query, start)
|
|
|
|
return tx.Tx.Exec(query, args...)
|
|
}
|
|
|
|
// ExecContext wraps sql.Tx.ExecContext to log slow queries
|
|
func (tx *loggingTx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
|
start := time.Now()
|
|
defer logSlowQuery(tx.logger, query, start)
|
|
|
|
return tx.Tx.ExecContext(ctx, query, args...)
|
|
}
|