recorder

package
v1.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

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:

  1. 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).

  2. 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

Constants

This section is empty.

Variables

This section is empty.

Functions

func Collect

func Collect(recs ...*Recorder) control.Invoked

Collect pliega varios recorders por-motor en un único control.Invoked listo para Manifest.Reconcile.

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.

const (
	OpExec     Op = "exec"      // ExecContext: INSERT/UPDATE/DELETE/DDL — filas = RowsAffected
	OpQuery    Op = "query"     // QueryContext: SELECT multi-fila — filas desconocidas en el wrap
	OpQueryRow Op = "query_row" // QueryRowContext: una fila lógica
)

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 New

func New(e control.Engine) *Recorder

New crea un Recorder para el motor e.

func (*Recorder) ContributeTo

func (r *Recorder) ContributeTo(inv control.Invoked)

ContributeTo vuelca la cobertura de este motor en inv (lo crea si falta).

func (*Recorder) Count

func (r *Recorder) Count() int

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) Engine

func (r *Recorder) Engine() control.Engine

Engine devuelve el motor de este Recorder.

func (*Recorder) Invoked

func (r *Recorder) Invoked() map[string]bool

Invoked devuelve una copia del set de símbolos ejercidos en este motor.

func (*Recorder) Mark

func (r *Recorder) Mark(ctx context.Context, symbol string) context.Context

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

func (r *Recorder) Note(symbols ...string)

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

func (r *Recorder) Options() []any

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

func (r *Recorder) Statements() []Statement

Statements devuelve una copia de los statements capturados, en orden.

func (*Recorder) Telemetry

func (r *Recorder) Telemetry() Telemetry

Telemetry devuelve una copia del agregado del observer.

func (*Recorder) WrapExec

func (r *Recorder) WrapExec(next quark.ExecFunc) quark.ExecFunc

WrapExec registra cada ExecContext (INSERT/UPDATE/DELETE/DDL) con su símbolo y las filas afectadas exactas.

func (*Recorder) WrapQuery

func (r *Recorder) WrapQuery(next quark.QueryFunc) quark.QueryFunc

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.

Jump to

Keyboard shortcuts

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