Help us shape the future of Go! Take the 2026 Go Developer Survey

dumps

package
v1.37.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package dumps receives, buffers, and fans out PHP `dump()`/`dd()` events captured by the lerd debug bridge (auto_prepend_file). The wire format is newline-delimited JSON. Production lerd-ui listens on a per-user Unix socket; tests bind TCP loopback. See docs/features/dumps.md.

Index

Constants

View Source
const (
	KindDump      = "dump"
	KindQuery     = "query"
	KindJob       = "job"
	KindView      = "view"
	KindMail      = "mail"
	KindCache     = "cache"
	KindEvent     = "event"
	KindHTTP      = "http"
	KindLog       = "log"
	KindException = "exception"
	KindMessage   = "message"
	// KindBrowser is a JavaScript error, console message or failed request
	// posted by the browser logs script rather than sent by PHP.
	KindBrowser = "browser"
)

Event kinds. KindDump (dump()/dd() output) was the first; the rest are emitted by the lerd_devtools Zend extension and the per-framework adapters (Laravel, Symfony). New kinds are added without bumping ProtocolVersion — the buffer and fan-out treat every kind identically, only per-kind consumers (UI lenses, query analysis) interpret Data.

View Source
const DefaultAddr = "127.0.0.1:9913"

DefaultAddr is the loopback bind address the receiver listens on when callers ask for tcp. Picked to avoid clashing with Symfony's `var-dump-server` default (9912) so users who already run it for some other purpose don't see surprise interceptions.

View Source
const DefaultCapacity = 5000

DefaultCapacity is how many events the ring keeps when dumps.buffer is unset, matching config.DefaultDumpsBuffer. An event-heavy request emits thousands, so 3000 let one push the requests before it out within seconds.

View Source
const DefaultNetwork = "unix"

DefaultNetwork is the listen network used by lerd-ui. Unix sockets are the default because the FPM containers can already reach the host home directory via the %h:%h bind mount — using a TCP loopback listener would mean opening the receiver to the entire host network ring just so containers could route through host.containers.internal.

View Source
const (
	// MaxLineBytes caps a single dump payload before bufio drops the line.
	// Sized to absorb VarCloner output for moderately large objects without
	// letting a runaway dump pin memory unboundedly.
	MaxLineBytes = 4 << 20 // 4 MiB

)
View Source
const ProtocolVersion = 1

ProtocolVersion is the wire-format version this package understands. Events with a different `v` are dropped.

View Source
const SlowMS = 100

SlowMS tags a query at or above it as slow, Telescope's default threshold.

Variables

This section is empty.

Functions

This section is empty.

Types

type Context

type Context struct {
	Type    string `json:"type"`
	Site    string `json:"site,omitempty"`
	Branch  string `json:"branch,omitempty"`
	Domain  string `json:"domain,omitempty"`
	Request string `json:"request,omitempty"`
	PID     int    `json:"pid,omitempty"`
	// RID is a unique per-request (FPM) / per-invocation (CLI) id stamped by
	// the lerd_devtools extension so consumers can group events by the exact
	// request, not just method+path+pid (which collapses repeat hits to the
	// same URL on a reused pool worker). dump()/dd() events from the pure-PHP
	// bridge carry a rid too, but when the extension isn't loaded the bridge's
	// rid() falls back to a fresh id per call, so it is NOT stable per request:
	// dump grouping must key on the request, not this field (see eventGroup.ts).
	RID string `json:"rid,omitempty"`
	// Worker names the queue/scheduler command this event came from (e.g.
	// "queue:work", "scrape:rtb-data"). Set only for worker-process events,
	// which are captured solely when the user opts in.
	Worker string `json:"worker,omitempty"`
	// Command is the CLI counterpart of Request: the invocation an event came
	// from ("artisan queue:work --queue=high"), stamped by the bridge for every
	// cli-SAPI process so console events can name where they happened.
	Command string `json:"command,omitempty"`
	// Test marks an event captured inside a PHPUnit/Pest run. The Debug lenses
	// hide these by default; they are tagged rather than dropped so a dump
	// added to diagnose a failing test stays one toggle away.
	Test bool `json:"test,omitempty"`
}

Context describes where a dump came from. Type is "fpm" (web request) or "cli" (artisan, tinker, queue worker). Empty fields are omitted on the wire. Branch is non-empty only when the event originated inside a git worktree (set by the bridge from LERD_BRANCH, injected by nginx for worktree vhosts and by lerd's CLI helpers when shelling into a worktree path).

type Event

type Event struct {
	V     int             `json:"v"`
	ID    string          `json:"id"`
	TS    string          `json:"ts"`
	Kind  string          `json:"kind"`
	Ctx   Context         `json:"ctx"`
	Src   Source          `json:"src"`
	Label string          `json:"label,omitempty"`
	Text  string          `json:"text,omitempty"`
	Tree  json.RawMessage `json:"tree,omitempty"`
	Data  json.RawMessage `json:"data,omitempty"`
	Trunc bool            `json:"trunc,omitempty"`
}

Event is one captured payload. For dumps, Text holds the rendered VarDumper output and Tree the pre-walked cloner tree. For every other kind, Data carries the kind-specific structured fields as opaque JSON (a query's sql/bindings/time, a job's class/status, …). The ring and hub never decode Data; only the UI lens and analysis helpers do.

func (Event) OfRequest added in v1.37.0

func (e Event) OfRequest(rid string) bool

OfRequest reports whether an event belongs to the request rid names: it ran in that request, or it is a browser event naming it as the request a fetch or XHR reached.

func (Event) Query added in v1.23.0

func (e Event) Query() (QueryData, bool)

Query decodes the Data payload as a QueryData. ok is false when the event is not a query or its payload does not decode.

func (Event) Valid

func (e Event) Valid() bool

Valid reports whether an event passes the minimum schema check applied by the listener before it is appended to the ring.

type FilterOpts

type FilterOpts struct {
	// Site exact-matches Ctx.Site when non-empty.
	Site string
	// Branch exact-matches Ctx.Branch when non-empty, isolating one git
	// worktree's events from the parent site they share a Site name with.
	Branch string
	// Ctx exact-matches Ctx.Type ("fpm" or "cli") when non-empty.
	Ctx string
	// Kind exact-matches Event.Kind when non-empty (e.g. "query", "dump").
	Kind string
	// RID keeps one request's events: those it ran, and a browser event that
	// names it as the request a fetch reached. A kept request is found even
	// after it left the buffer.
	RID string
	// SinceID drops events whose ID is lexicographically <= SinceID.
	SinceID string
	// Before keeps only events whose ID sorts before it, so a list pages back
	// from the oldest row it already shows.
	Before string
	// HideTests leaves out events captured inside a test run.
	HideTests bool
	// Route keeps one route as the timing view names it ("GET /users/:id").
	Route string
	// Limit caps the returned slice to the most recent N entries.
	// Zero or negative means no limit.
	Limit int
}

FilterOpts narrows a Snapshot. Zero-value fields are ignored.

type Group added in v1.37.0

type Group struct {
	Key       string  `json:"key"`
	Count     int     `json:"count"`
	TotalMS   float64 `json:"total_ms"`
	SlowCount int     `json:"slow_count"`
	NPlusOne  bool    `json:"n_plus_one"`
	Rows      []Row   `json:"rows"`
	// contains filtered or unexported fields
}

Group is one request in a lens, its newest Rows rows first.

type GroupOpts added in v1.37.0

type GroupOpts struct {
	FilterOpts
	// Search matches the lens's text: a query's SQL, a dump's output, any
	// other kind's payload, and every event's request, route and id.
	Search string
	// Worker keeps one queue or scheduler command's events.
	Worker string
	// HideWorkers leaves out what worker processes emitted, except jobs, which
	// are the only sign a queue is being drained.
	HideWorkers bool
	// Facet keeps one job status, log level or browser event type.
	Facet string
	// Before is a page's Next, to read the groups older than that page.
	Before int64
	// Limit is how many groups a page holds, Rows how many rows each carries.
	Limit int
	Rows  int
}

GroupOpts narrows a lens. FilterOpts carries the scope (site, branch, kind, request, test runs); the rest are the lens's own controls.

type GroupPage added in v1.37.0

type GroupPage struct {
	Groups []Group `json:"groups"`
	Next   int64   `json:"next"`
	Total  int     `json:"total"`
}

GroupPage is one page of a lens. Next reads the page after it, 0 at the end; Total is every event the lens matches, across all its pages.

type Hub

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

Hub fans Events out to subscribers. Publish is non-blocking; subscribers that don't drain fast enough drop events instead of stalling the listener.

func NewHub

func NewHub() *Hub

NewHub returns an empty Hub.

func (*Hub) Count

func (h *Hub) Count() int

Count returns the number of active subscribers (for status/diagnostics).

func (*Hub) Publish

func (h *Hub) Publish(e Event)

Publish delivers e to every active subscriber. Subscribers whose buffer is full miss the event; the publisher never blocks.

func (*Hub) Subscribe

func (h *Hub) Subscribe() (<-chan Event, func())

Subscribe returns a buffered channel that receives every subsequently published event, plus an unsubscribe func that closes the channel and removes it from the hub. The unsubscribe is idempotent.

type QueryData added in v1.23.0

type QueryData struct {
	SQL        string        `json:"sql"`
	Bindings   []interface{} `json:"bindings,omitempty"`
	TimeMS     float64       `json:"time_ms"`
	Connection string        `json:"connection,omitempty"`
	RWType     string        `json:"rw_type,omitempty"`
}

QueryData is the Data payload for KindQuery events. The lerd_devtools extension fills sql/bindings/time_ms from the agnostic PDO/mysqli hook; the Laravel adapter (QueryExecuted) additionally sets Connection and RWType. The originating file:line lives in Event.Src, like dumps.

type Ring

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

Ring is the debug buffer: the newest cap events, plus every event of the kept requests however old. It lives in SQLite rather than memory, since a single slow page can carry thousands of events and lerd-ui has to stay small; a reader decodes only what it asked for. Safe for concurrent use.

func NewRing

func NewRing(capacity int) *Ring

NewRing returns a ring held in an in-memory database, for a process that does not need the buffer to outlive it.

func OpenRing added in v1.37.0

func OpenRing(path string, capacity int) (*Ring, error)

OpenRing opens (creating if needed) the ring stored at path, so the buffer survives a lerd-ui restart. Non-positive capacity means DefaultCapacity.

func (*Ring) Append

func (r *Ring) Append(e Event)

Append stores e, dropping the oldest event once the ring is full unless it belongs to a kept request.

func (*Ring) Cap

func (r *Ring) Cap() int

Cap returns the maximum number of events the buffer holds.

func (*Ring) Clear

func (r *Ring) Clear()

Clear empties the ring, kept requests included.

func (*Ring) Close added in v1.37.0

func (r *Ring) Close() error

Close releases the database.

func (*Ring) Counts added in v1.37.0

func (r *Ring) Counts(opts FilterOpts) map[string]int

Counts is how many events of each kind opts selects, page views aside: the lens bar's badges, counted where the events are rather than in a tab.

func (*Ring) Event added in v1.37.0

func (r *Ring) Event(id string) (json.RawMessage, bool)

Event is one whole event by id, for a row a lens opens.

func (*Ring) FacetValues added in v1.37.0

func (r *Ring) FacetValues(opts FilterOpts) []string

FacetValues lists the facet values opts's kind has in its scope: a job's statuses, a log's levels, a message's channels, a browser event's types.

func (*Ring) Filter

func (r *Ring) Filter(opts FilterOpts) []Event

Filter returns the events opts selects, oldest first.

func (*Ring) FilterJSON added in v1.37.0

func (r *Ring) FilterJSON(opts FilterOpts) []byte

FilterJSON is Filter encoded as a JSON array, built from the stored rows as they are, so serving thousands of events costs one copy rather than a decode and an encode of each.

func (*Ring) GroupRows added in v1.37.0

func (r *Ring) GroupRows(opts GroupOpts, key string, before int64) []Row

GroupRows reads more of one group's rows, the ones older than the row at before, newest first. Paging from a row rather than an offset keeps events that land in the group meanwhile from handing back a row already shown.

func (*Ring) Groups added in v1.37.0

func (r *Ring) Groups(opts GroupOpts) GroupPage

Groups returns one page of opts's lens: the requests with the latest activity first, each with its count, query time and N+1 flag.

func (*Ring) Import added in v1.37.0

func (r *Ring) Import(path string) error

Import appends the events an older lerd-ui saved to a JSON file at path, oldest first, and deletes the file once every one is on disk. Until then it is their only copy, so a write that fails, or a ring held in memory, leaves it for the next start. A missing file is nothing to import.

func (*Ring) Len

func (r *Ring) Len() int

Len returns how many events the buffer holds, kept requests aside.

func (*Ring) Remove added in v1.36.0

func (r *Ring) Remove(drop func(Event) bool)

Remove drops every event drop matches, kept requests included.

func (*Ring) RequestIDs added in v1.37.0

func (r *Ring) RequestIDs() map[string]bool

RequestIDs is the set of requests with at least one event in the ring: the ones a recent request's Inspect can open on something.

func (*Ring) Resize added in v1.37.0

func (r *Ring) Resize(capacity int)

Resize changes how many events the ring keeps, dropping the oldest that no longer fit unless a kept request ran them.

func (*Ring) SetKeep added in v1.37.0

func (r *Ring) SetKeep(keep map[string]bool)

SetKeep replaces the set of requests whose events outlive the buffer, and lets go of the ones no longer in it.

func (*Ring) Sites added in v1.37.0

func (r *Ring) Sites() []string

Sites lists every site with an event in the buffer, for the site filter.

func (*Ring) Snapshot

func (r *Ring) Snapshot() []Event

Snapshot returns the buffer, the newest cap events, oldest first.

func (*Ring) TestCount added in v1.37.0

func (r *Ring) TestCount(opts FilterOpts) int

TestCount is how many test-run events opts would select with them shown, for the hint that some are hidden.

func (*Ring) Workers added in v1.37.0

func (r *Ring) Workers(opts FilterOpts) []string

Workers lists the worker commands with events in opts's scope, for the lens command filter.

type Row added in v1.37.0

type Row struct {
	Event json.RawMessage `json:"event"`
	Dup   int             `json:"dup"`
	Seq   int64           `json:"seq"`
}

Row is one event and, for a query, how often its fingerprint ran in the request (1 when unique). Seq is its place in the buffer, which reading more of the group pages back from.

type Server

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

Server accepts loopback NDJSON connections from the PHP debug bridge, validates each line against ProtocolVersion, appends valid events to the ring, and publishes them to subscribers. Close once via Close().

func Listen

func Listen(ctx context.Context, addr string) (*Server, error)

Listen binds a TCP listener on addr and starts the accept loop. If addr is empty, DefaultAddr is used. The returned Server keeps running until Close is called or ctx is cancelled. Kept for tests and existing callers that already pass a TCP address; production lerd-ui uses ListenOn with "unix" so the receiver isn't reachable from the host network ring.

func ListenOn

func ListenOn(ctx context.Context, network, addr string) (*Server, error)

ListenOn binds on the given network and address. network is either "tcp" or "unix"; for "unix", any pre-existing socket at addr is removed first so a previous lerd-ui crash doesn't pin the path forever.

func ListenWithRing added in v1.37.0

func ListenWithRing(ctx context.Context, network, addr string, ring *Ring) (*Server, error)

ListenWithRing is ListenOn buffering into ring, such as one OpenRing keeps on disk so the buffer survives a restart.

func (*Server) Addr

func (s *Server) Addr() string

Addr returns the bound address, useful when Listen was called with :0.

func (*Server) Cap added in v1.37.0

func (s *Server) Cap() int

Cap returns how many events the server keeps, and Resize changes it.

func (*Server) Clear

func (s *Server) Clear()

Clear empties the ring. Active subscribers continue to receive events.

func (*Server) ClearKind added in v1.37.0

func (s *Server) ClearKind(kind string)

ClearKind drops the buffered events of one kind and keeps the rest.

func (*Server) Close

func (s *Server) Close() error

Close stops accepting connections, closes in-flight reads, and waits for outstanding goroutines to drain. Safe to call multiple times.

func (*Server) Counts added in v1.37.0

func (s *Server) Counts(opts FilterOpts) map[string]int

Counts, TestCount, Groups, GroupRows, Sites and Workers are the Debug lenses' queries; see the Ring methods of the same names.

func (*Server) Event added in v1.37.0

func (s *Server) Event(id string) (json.RawMessage, bool)

func (*Server) FacetValues added in v1.37.0

func (s *Server) FacetValues(opts FilterOpts) []string

func (*Server) Filter

func (s *Server) Filter(opts FilterOpts) []Event

Filter returns a filtered Snapshot.

func (*Server) FilterJSON added in v1.37.0

func (s *Server) FilterJSON(opts FilterOpts) []byte

FilterJSON is Filter as the JSON array the API serves.

func (*Server) ForgetRequests added in v1.37.0

func (s *Server) ForgetRequests(rids []string)

ForgetRequests drops every buffered event of the given requests, as their history is removed from request timing.

func (*Server) GroupRows added in v1.37.0

func (s *Server) GroupRows(opts GroupOpts, key string, before int64) []Row

func (*Server) Groups added in v1.37.0

func (s *Server) Groups(opts GroupOpts) GroupPage

func (*Server) Import added in v1.37.0

func (s *Server) Import(path string) error

Import takes in the buffer an older lerd-ui saved as JSON at path.

func (*Server) Len

func (s *Server) Len() int

Len returns the number of buffered events.

func (*Server) Push

func (s *Server) Push(e Event)

Push injects an event as if it had arrived on the wire. Used by tests to avoid juggling sockets when only ring/hub semantics matter.

func (*Server) RequestIDs added in v1.37.0

func (s *Server) RequestIDs() map[string]bool

RequestIDs is the set of requests with captured events still buffered.

func (*Server) Resize added in v1.37.0

func (s *Server) Resize(capacity int)

func (*Server) SetKeep added in v1.37.0

func (s *Server) SetKeep(keep map[string]bool)

SetKeep names the requests whose events outlive the buffer.

func (*Server) SetKeepTests added in v1.36.0

func (s *Server) SetKeepTests(keep bool)

SetKeepTests switches recording of test-run events. Switching it off also drops the ones already buffered, since the space they hold is the reason.

func (*Server) SetSiteResolver added in v1.37.0

func (s *Server) SetSiteResolver(fn func(string) string)

SetSiteResolver sets how an incoming event's site name is mapped to the registered site before the event is stored.

func (*Server) Sites added in v1.37.0

func (s *Server) Sites() []string

func (*Server) Snapshot

func (s *Server) Snapshot() []Event

Snapshot returns a copy of the ring in insertion order.

func (*Server) Subscribe

func (s *Server) Subscribe() (<-chan Event, func())

Subscribe returns a buffered channel of new events plus an unsubscribe func.

func (*Server) Subscribers

func (s *Server) Subscribers() int

Subscribers returns the current subscriber count.

func (*Server) TestCount added in v1.37.0

func (s *Server) TestCount(opts FilterOpts) int

func (*Server) Workers added in v1.37.0

func (s *Server) Workers(opts FilterOpts) []string

type Source

type Source struct {
	File string `json:"file"`
	Line int    `json:"line"`
}

Source identifies the file:line that produced a dump.

Jump to

Keyboard shortcuts

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