slowquery

package
v0.96.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 7, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MetricsCollector added in v0.63.0

func MetricsCollector(s *SlowQueryLogger) func(io.Writer)

MetricsCollector returns a Prometheus text-exposition collector emitting slow_queries_total (the running count of queries that crossed the logger's threshold). Register it on the app's *middleware.Metrics via RegisterCollector so the count surfaces on the single /metrics endpoint.

A nil *SlowQueryLogger reports zero, so wiring the collector before the logger exists (or when slow-query logging is disabled) never panics /metrics.

func TrimSQL

func TrimSQL(q string) string

TrimSQL is the statement's shape, as the slow-query line prints it when no dialect was named: every string and number literal replaced by ?, comments dropped, whitespace collapsed, control bytes escaped, and the result capped at 240 bytes (cut on a rune boundary, then "…") to keep logs from exploding on big builders. Placeholders ($1, ?, :n) and identifiers stay. Bound arguments were never logged, only their count.

A slow-query line is for the statement's shape, and a value spelled inline (ALTER ROLE … PASSWORD '…', SET app.key = '…') went to every sink verbatim. Where a literal ends depends on the engine, and TrimSQL does not know it, so it masks under every engine's rules at once: "double-quoted" text prints as ? too (SQLite and MySQL can read it as a string), # opens a comment (MySQL), block comments nest (PostgreSQL), and a string whose end depends on whether a backslash escapes masks the rest of the statement. Name the engine with WithDialect to keep quoted identifiers on PostgreSQL. It is the masker core/tracing puts on db.query.text.

Types

type Option added in v0.96.0

type Option func(*SlowQueryLogger)

Option configures a SlowQueryLogger.

func WithDialect added in v0.96.0

func WithDialect(name string) Option

WithDialect names the database engine, so the sql attr masks its literals by that engine's quoting rules: "postgres" (or "postgresql", "pgx"), "sqlite3" (or "sqlite"), "mysql" (or "mariadb"). The values of framework.DetectDialect are accepted as they are. Without it, or with a name it does not know, the line masks under every engine's rules at once (see TrimSQL), which also hides PostgreSQL's "quoted identifiers".

type SlowQueryLogger

type SlowQueryLogger struct {
	// contains filtered or unexported fields
}

SlowQueryLogger emits a slog warning for any DB query whose execution time exceeds Threshold. Wrap the framework's *sql.DB at construction time (or any db.Executor) and pass the result into NewCrudHandler in place of the raw DB.

Threshold of 0 disables logging entirely (default zero-value).

The wrapper is dialect-agnostic, it simply times QueryContext / QueryRowContext / ExecContext on the underlying connection and emits a structured log line when the duration crosses the threshold.

func NewSlowQueryLogger

func NewSlowQueryLogger(inner db.Executor, threshold time.Duration, logger *slog.Logger, opts ...Option) *SlowQueryLogger

NewSlowQueryLogger wraps inner with a slow-query observer. When threshold is zero, the wrapper is a no-op pass-through (the same db.Executor with no instrumentation cost).

logger is a pinned *slog.Logger. Slow-query lines write through it for the lifetime of the wrapper. To follow App.Logger swaps (battery/log replaces it during plugin Init), use NewSlowQueryLoggerFn instead and pass app.Logger as the accessor.

func NewSlowQueryLoggerFn

func NewSlowQueryLoggerFn(inner db.Executor, threshold time.Duration, getLogger func() *slog.Logger, opts ...Option) *SlowQueryLogger

NewSlowQueryLoggerFn is like NewSlowQueryLogger but takes a per-call accessor so log lines route through the current logger at observation time. Use with app.Logger so battery/log's SetLogger swap takes effect without re-wrapping the executor.

If getLogger is nil or returns nil, slog.Default is used as a safety fallback (slow-query lines never disappear silently).

func (*SlowQueryLogger) BeginTx

func (s *SlowQueryLogger) BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)

BeginTx forwards transaction starts to the inner DB if it supports them. Tx-bound queries don't go through this wrapper (the framework hands the raw *sql.Tx to the in-tx handler copy), so multi-statement transactions aren't slow-logged here today. A future enhancement could wrap the tx too.

func (*SlowQueryLogger) ExecContext

func (s *SlowQueryLogger) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)

ExecContext mirrors sql.DB.ExecContext, timing the call.

func (*SlowQueryLogger) Hits

func (s *SlowQueryLogger) Hits() uint64

Hits returns the running count of queries that crossed the threshold. Useful for assertions in tests and for /.debug/stats surface metrics.

func (*SlowQueryLogger) QueryContext

func (s *SlowQueryLogger) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)

QueryContext mirrors sql.DB.QueryContext, timing the call.

func (*SlowQueryLogger) QueryRowContext

func (s *SlowQueryLogger) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row

QueryRowContext mirrors sql.DB.QueryRowContext, timing the call.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL