Log slow API requests with server spans and client timing
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -85,15 +86,15 @@ func migratePrefixIDs(tx *sql.Tx, dataDir string) error {
|
||||
for i, w := range worktrees {
|
||||
worktrees[i] = filepath.Dir(w)
|
||||
}
|
||||
err = git.RepairWorktrees(repo, worktrees)
|
||||
err = git.RepairWorktrees(context.Background(), repo, worktrees)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = git.RenameRefs(repo, rewrite)
|
||||
err = git.RenameRefs(context.Background(), repo, rewrite)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = git.RewriteNotes(repo, rewrite)
|
||||
err = git.RewriteNotes(context.Background(), repo, rewrite)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
|
||||
"g.fc.run/ai/byre/internal/api"
|
||||
"g.fc.run/ai/byre/internal/trace"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("not found")
|
||||
@@ -85,10 +84,11 @@ type Store struct {
|
||||
|
||||
func Open(path string, portFirst int, onEvent func([]api.Event)) (*Store, error) {
|
||||
dsn := "file:" + path + "?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)&_txlock=immediate"
|
||||
db, err := sql.Open("sqlite", dsn)
|
||||
connector, err := newTracedConnector(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db := sql.OpenDB(connector)
|
||||
|
||||
err = migrate(db, filepath.Dir(path))
|
||||
if err != nil {
|
||||
@@ -1505,7 +1505,9 @@ func (s *Store) Counts(ctx context.Context) (Counts, error) {
|
||||
type emitFunc func(api.Event) error
|
||||
|
||||
func (s *Store) write(ctx context.Context, fn func(tx *sql.Tx, emit emitFunc) error) error {
|
||||
locked := trace.Start(ctx, "store lock")
|
||||
s.writeMu.Lock()
|
||||
locked()
|
||||
defer s.writeMu.Unlock()
|
||||
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
|
||||
"modernc.org/sqlite"
|
||||
|
||||
"g.fc.run/ai/byre/internal/trace"
|
||||
)
|
||||
|
||||
type sqliteConn interface {
|
||||
driver.Conn
|
||||
driver.ConnBeginTx
|
||||
driver.ConnPrepareContext
|
||||
driver.ExecerContext
|
||||
driver.QueryerContext
|
||||
driver.Pinger
|
||||
driver.SessionResetter
|
||||
driver.Validator
|
||||
}
|
||||
|
||||
type tracedConnector struct {
|
||||
driver.Connector
|
||||
}
|
||||
|
||||
func newTracedConnector(dsn string) (driver.Connector, error) {
|
||||
c, err := sqlite.NewConnector(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tracedConnector{c}, nil
|
||||
}
|
||||
|
||||
func (c tracedConnector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||
conn, err := c.Connector.Connect(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tracedConn{conn.(sqliteConn)}, nil
|
||||
}
|
||||
|
||||
type tracedConn struct {
|
||||
sqliteConn
|
||||
}
|
||||
|
||||
func (c tracedConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||
defer trace.Start(ctx, "sql begin")()
|
||||
return c.sqliteConn.BeginTx(ctx, opts)
|
||||
}
|
||||
|
||||
func (c tracedConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
|
||||
defer trace.Start(ctx, "sql exec")()
|
||||
return c.sqliteConn.ExecContext(ctx, query, args)
|
||||
}
|
||||
|
||||
func (c tracedConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
|
||||
start := time.Now()
|
||||
rows, err := c.sqliteConn.QueryContext(ctx, query, args)
|
||||
if err != nil {
|
||||
trace.Add(ctx, "sql query", time.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
return &tracedRows{sqliteRows: rows.(sqliteRows), ctx: ctx, took: time.Since(start)}, nil
|
||||
}
|
||||
|
||||
type sqliteRows interface {
|
||||
driver.Rows
|
||||
driver.RowsColumnTypeDatabaseTypeName
|
||||
driver.RowsColumnTypeLength
|
||||
driver.RowsColumnTypeNullable
|
||||
driver.RowsColumnTypePrecisionScale
|
||||
driver.RowsColumnTypeScanType
|
||||
}
|
||||
|
||||
type tracedRows struct {
|
||||
sqliteRows
|
||||
ctx context.Context
|
||||
took time.Duration
|
||||
}
|
||||
|
||||
func (r *tracedRows) Next(dest []driver.Value) error {
|
||||
start := time.Now()
|
||||
err := r.sqliteRows.Next(dest)
|
||||
r.took += time.Since(start)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *tracedRows) Close() error {
|
||||
start := time.Now()
|
||||
err := r.sqliteRows.Close()
|
||||
trace.Add(r.ctx, "sql query", r.took+time.Since(start))
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user