Open feikeq opened 2 months ago
You could try wrapping the database driver with sqlhooks
. This suggestion originally came from a StackOverflow post, though I haven't been able to locate it again.
var logger *slog.Logger
const SlowThreshold = 300 * time.Millisecond
func init() {
hook := customHook{
slowThreshold: SlowThreshold,
}
sql.Register("mysql-custom", sqlhooks.Wrap(&mysql.MySQLDriver{}, &hook))
}
type customHook struct {
slowThreshold time.Duration
}
// make sure hook implement `sqlhooks.Hooks`
var _ interface{ sqlhooks.Hooks } = (*customHook)(nil)
type hookKey string
const hookStartAt hookKey = "startAt"
func (h *customHook) Before(ctx context.Context, query string, args ...any) (context.Context, error) {
ctx = context.WithValue(ctx, hookStartAt, time.Now())
return ctx, nil
}
// not run if on error
func (h *customHook) After(ctx context.Context, query string, args ...any) (context.Context, error) {
if startAt, ok := ctx.Value(hookStartAt).(time.Time); ok {
if took := time.Since(startAt); took >= h.slowThreshold { // warn if slow
logger.Warn("slow query",
slog.String("query", string(readFriendly(query))),
slog.Any("args", args),
slog.Int64("took", int64(took)))
}
}
return ctx, nil
}
type ErrDown struct {
err error
query string
args []any
took time.Duration
}
// OnError will be called if any error happens
func (h *customHook) OnError(ctx context.Context, err error, query string, args ...any) error {
// Not a user error: driver is telling sql package that an
// optional interface method is not implemented. There is
// nothing to instrument here.
// https://golang.org/pkg/database/sql/driver/#ErrSkip
// https://github.com/DataDog/dd-trace-go/issues/270
if errors.Is(err, driver.ErrSkip) {
return nil
}
if err == nil {
return nil
}
custom := ErrDown{
err: err,
query: query,
args: args,
}
if startAt, ok := ctx.Value(hookStartAt).(time.Time); ok {
custom.took = time.Since(startAt)
}
return custom
}
没有这功能在调式的时候很不方便啊!