Documentation
¶
Overview ¶
Package recorder instrumenta un Client de Quark para la superapp de aceptación: observa cada statement SQL y lo atribuye al símbolo de la API pública que lo originó, alimentando dos mecanismos del arnés:
COBERTURA (control.Invoked) — qué símbolos públicos se ejercieron en este motor. La alimentan Mark/Note en cada call-site del exerciser; NO se deriva del SQL, porque la mayoría de símbolos (builders como Where/OrderBy, opciones, tipos) no emiten SQL propio. Es el numerador del gate de manifiesto (control.Manifest.Reconcile).
CAPTURA DE SQL (Statements) — el SQL parametrizado por símbolo y motor, para los golden snapshots y el oráculo de paridad cross-engine, más el conteo de statements que sostiene las aserciones "cache hit = 0 SQL" y "N+1 acotado" de los exercisers.
El Recorder se engancha por DOS vías complementarias de Quark, porque ninguna sola da la tupla completa (símbolo, motor, sql, duración, filas):
- quark.Middleware (WrapExec/WrapQuery/WrapQueryRow) — recibe context, así que lee el símbolo estampado por Mark: es la fuente AUTORITATIVA del par (símbolo → SQL). Mide la duración y, para EXEC/QUERY_ROW, las filas exactas (RowsAffected / 1).
- quark.QueryObserver (ObserveQuery) — NO recibe context (no ve el símbolo), pero Quark lo invoca tras escanear, así que reporta el conteo de filas exacto también para los SELECT multi-fila, que el middleware no puede contar sin consumir el *sql.Rows del caller. Mantiene un agregado por motor y completa best-effort las filas del último statement multi-fila pendiente con el mismo SQL.
Un Recorder es POR MOTOR. El símbolo activo viaja por context (inmune a carreras entre goroutines); el estado mutable (invoked/stmts/tele) está protegido por mu, de modo que el Recorder es seguro bajo los exercisers concurrentes (ha.go: pool exhaustion, deadlock retry).
Index ¶
- func Collect(recs ...*Recorder) control.Invoked
- type Op
- type Recorder
- func (r *Recorder) ContributeTo(inv control.Invoked)
- func (r *Recorder) Count() int
- func (r *Recorder) Engine() control.Engine
- func (r *Recorder) Invoked() map[string]bool
- func (r *Recorder) Mark(ctx context.Context, symbol string) context.Context
- func (r *Recorder) Note(symbols ...string)
- func (r *Recorder) ObserveQuery(ev quark.QueryEvent)
- func (r *Recorder) Options() []any
- func (r *Recorder) Reset()
- func (r *Recorder) Statements() []Statement
- func (r *Recorder) Telemetry() Telemetry
- func (r *Recorder) WrapExec(next quark.ExecFunc) quark.ExecFunc
- func (r *Recorder) WrapQuery(next quark.QueryFunc) quark.QueryFunc
- func (r *Recorder) WrapQueryRow(next quark.QueryRowFunc) quark.QueryRowFunc
- type Statement
- type Telemetry
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Op ¶
type Op string
Op clasifica un statement por la primitiva de Quark que lo ejecutó. No es el verbo SQL (eso lo da QueryEvent.Operation en la telemetría); es la vía de ejecución, que determina qué se sabe de las filas en el momento del wrap.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder instrumenta un Client de un motor concreto. Implementa quark.Middleware y quark.QueryObserver; las aserciones de compilación de abajo garantizan que las firmas siguen casando con la API real de Quark.
func (*Recorder) ContributeTo ¶
ContributeTo vuelca la cobertura de este motor en inv (lo crea si falta).
func (*Recorder) Count ¶
Count es cuántos statements SQL se han registrado. Para las aserciones de conteo: tómalo antes y después de una operación de servicio y diffea (p.ej. un cache hit no debe incrementarlo; un Preload de N hijos debe sumar 1, no N).
func (*Recorder) Mark ¶
Mark estampa symbol en ctx Y lo marca como ejercido en este motor. El ctx devuelto debe pasarse a quark.For/ForTx en el call-site, para que el SQL que dispare quede atribuido a ese símbolo:
ctx = rec.Mark(ctx, "github.com/jcsvwinston/quark.(*Query[T]).List") rows, err := quark.For[domain.Account](ctx, client).List()
func (*Recorder) Note ¶
Note marca símbolos como ejercidos SIN tocar el context. Para los que no emiten SQL ni se enhebran por una llamada con ctx: constructores de opciones, tipos puros, helpers (p.ej. quark.DefaultLimits, quark.WithReplicas).
func (*Recorder) ObserveQuery ¶
func (r *Recorder) ObserveQuery(ev quark.QueryEvent)
ObserveQuery recibe el evento que Quark emite tras escanear: aporta el conteo de filas exacto (incluido el de los SELECT multi-fila) al agregado y completa best-effort las filas del último statement multi-fila pendiente con el mismo SQL. La completitud es EXACTA bajo ejecución secuencial en una goroutine (el observer del SELECT dispara justo tras el middleware que lo registró); sólo aproximada si dos goroutines corren el MISMO SQL en paralelo — y aun así nunca atribuye mal el SÍMBOLO, que proviene del context autoritativo del middleware.
func (*Recorder) Options ¶
Options devuelve las opciones que instalan este Recorder como middleware Y observer en un Client. Se pasan a quark.New tal cual:
rec := recorder.New(control.SQLite)
client, _ := quark.New("sqlite", dsn, rec.Options()...)
func (*Recorder) Reset ¶
func (r *Recorder) Reset()
Reset limpia statements y telemetría CONSERVANDO la cobertura acumulada. Para acotar conteos entre fases de un mismo motor sin perder lo ya invocado.
func (*Recorder) Statements ¶
Statements devuelve una copia de los statements capturados, en orden.
func (*Recorder) WrapExec ¶
WrapExec registra cada ExecContext (INSERT/UPDATE/DELETE/DDL) con su símbolo y las filas afectadas exactas.
func (*Recorder) WrapQuery ¶
WrapQuery registra cada QueryContext (SELECT multi-fila). Las filas no se pueden contar aquí sin consumir el *sql.Rows que el caller necesita escanear, así que se dejan en -1 y ObserveQuery las completa tras el escaneo.
func (*Recorder) WrapQueryRow ¶
func (r *Recorder) WrapQueryRow(next quark.QueryRowFunc) quark.QueryRowFunc
WrapQueryRow registra cada QueryRowContext (una fila lógica). *sql.Row difiere su error a Scan, así que Err queda nil aquí — igual que el evento de observer QUERY_ROW de Quark.
type Statement ¶
type Statement struct {
Symbol string // Symbol.Key() del símbolo activo (vacío si no se estampó)
Engine control.Engine // motor de este Recorder
SQL string // SQL parametrizado (sin valores de bind — principio de redacción F4-2)
Op Op
Dur time.Duration
Rows int64
Err error
}
Statement es un statement SQL capturado, atribuido al símbolo que lo originó. Rows vale -1 cuando la vía no permite conocer el conteo en el wrap (SELECT multi-fila no enriquecido por el observer todavía).
type Telemetry ¶
type Telemetry struct {
Queries int // número de eventos de observer (≈ statements reales)
Rows int64 // suma de filas reportadas (>0)
ByOp map[string]int // QueryEvent.Operation -> conteo (SELECT/EXEC/QUERY_ROW/...)
}
Telemetry es el agregado por motor que alimenta el observer. Da el conteo de filas exacto incluso para SELECT multi-fila, que el middleware no ve.