Documentation
¶
Overview ¶
Package metrics records latencies and counters during a run and merges them losslessly across intervals and workers.
Index ¶
- Constants
- Variables
- func TraceIDString(id [16]byte) string
- type Bucket
- type Collector
- func (c *Collector) Dropped(n uint64)
- func (c *Collector) Flush(interval int64, vus int, planned float64) *Snapshot
- func (c *Collector) IterationDone(vu, journey int, d time.Duration, ok bool)
- func (c *Collector) IterationStarted(vu, journey int, lag time.Duration)
- func (c *Collector) PhaseHistograms() map[int]*[NumPhases]*Histogram
- func (c *Collector) Record(vu int, s *Sample)
- type ErrorExample
- type Histogram
- func (h *Histogram) Buckets() []Bucket
- func (h *Histogram) Clone() *Histogram
- func (h *Histogram) Count() uint64
- func (h *Histogram) MarshalBinary() ([]byte, error)
- func (h *Histogram) MarshalText() ([]byte, error)
- func (h *Histogram) Max() uint64
- func (h *Histogram) Mean() float64
- func (h *Histogram) Merge(o *Histogram)
- func (h *Histogram) Min() uint64
- func (h *Histogram) Quantile(q float64) uint64
- func (h *Histogram) QuantileSeconds(q float64) float64
- func (h *Histogram) Quantiles(qs ...float64) []uint64
- func (h *Histogram) Record(us uint64)
- func (h *Histogram) RecordDuration(d time.Duration)
- func (h *Histogram) RecordN(us uint64, n uint64)
- func (h *Histogram) Reset()
- func (h *Histogram) Sum() uint64
- func (h *Histogram) Summary() Percentiles
- func (h *Histogram) UnmarshalBinary(data []byte) error
- func (h *Histogram) UnmarshalText(text []byte) error
- type JourneyStats
- type Percentiles
- type Phase
- type Sample
- type SlowRequest
- type Snapshot
- type StepStats
Constants ¶
const MaxErrorExamples = 3
MaxErrorExamples is how many examples a step keeps for each error.
const MaxExampleBody = 512
MaxExampleBody bounds the request and response bodies of an example.
const MaxSlowest = 5
MaxSlowest is how many of the slowest requests a step keeps per interval and for the whole run.
Variables ¶
var PhaseNames = [NumPhases]string{"dns", "connect", "tls", "wait", "download", "firstEvent", "fcp", "lcp", "cls", "inp", "load"}
PhaseNames are the report labels for each phase.
Functions ¶
func TraceIDString ¶
TraceIDString returns the trace ID as 32 hex digits, or "" when unset.
Types ¶
type Collector ¶
type Collector struct {
// contains filtered or unexported fields
}
Collector receives samples from many virtual users concurrently and produces one Snapshot per interval. Users are spread over lock-striped shards so recording does not contend on a single mutex.
func NewCollector ¶
NewCollector creates a collector with n shards (at least 1).
func (*Collector) Dropped ¶
Dropped counts iterations that could not start because no user was free.
func (*Collector) Flush ¶
Flush closes the current interval and returns its snapshot. vus and planned are gauges sampled by the caller at flush time.
func (*Collector) IterationDone ¶
IterationDone counts a finished iteration.
func (*Collector) IterationStarted ¶
IterationStarted counts a journey iteration starting, along with how late it was dispatched compared with its schedule.
func (*Collector) PhaseHistograms ¶
PhaseHistograms returns run-wide per-phase histograms for every step.
type ErrorExample ¶
type ErrorExample struct {
At time.Time `json:"at"`
TraceID string `json:"traceId,omitempty"`
// Request is "METHOD URL"; RequestBody its first MaxExampleBody bytes.
Request string `json:"request"`
RequestHeaders map[string]string `json:"requestHeaders,omitempty"`
RequestBody string `json:"requestBody,omitempty"`
Status int `json:"status,omitempty"`
ResponseHeaders map[string]string `json:"responseHeaders,omitempty"`
ResponseBody string `json:"responseBody,omitempty"`
// Detail is the error message, such as a check's mismatch or a
// connection error.
Detail string `json:"detail,omitempty"`
// Browser steps: a JPEG screenshot of the page when it failed, its
// console errors and warnings, and a HAR of its requests (no bodies).
Screenshot []byte `json:"screenshot,omitempty"`
Console []string `json:"console,omitempty"`
HAR string `json:"har,omitempty"`
}
ErrorExample shows one failed request: what was sent and what came back, with credentials and the run's secrets redacted.
type Histogram ¶
type Histogram struct {
// contains filtered or unexported fields
}
Histogram is a log-linear latency histogram with the same bucketing as HdrHistogram at 3 significant digits: values below 2048 µs are exact and larger values are kept within 0.1% relative error. Storage is chunked and allocated on demand, so a histogram covering a narrow latency band costs a few KB instead of HdrHistogram's ~140 KB dense array. That matters because a worker keeps one per step per second.
Values are recorded in microseconds. Histograms are not safe for concurrent use.
func (*Histogram) MarshalBinary ¶
MarshalBinary encodes the histogram compactly (sparse, varint).
func (*Histogram) MarshalText ¶
MarshalText encodes the histogram as base64 of its binary form, so it can travel inside JSON.
func (*Histogram) Quantile ¶
Quantile returns the value at quantile q (0..1) in µs, reported as the highest value equivalent to the bucket, as HdrHistogram does. The result never exceeds the recorded maximum.
func (*Histogram) QuantileSeconds ¶
QuantileSeconds is Quantile converted to seconds.
func (*Histogram) Quantiles ¶
Quantiles returns several quantiles in one pass. qs must be ascending.
func (*Histogram) RecordDuration ¶
RecordDuration adds one duration, rounded to microseconds.
func (*Histogram) Reset ¶
func (h *Histogram) Reset()
Reset empties the histogram, keeping allocated chunks for reuse.
func (*Histogram) Summary ¶
func (h *Histogram) Summary() Percentiles
Summary computes the standard percentile set in seconds.
func (*Histogram) UnmarshalBinary ¶
UnmarshalBinary decodes data produced by MarshalBinary, replacing h.
func (*Histogram) UnmarshalText ¶
UnmarshalText decodes MarshalText output.
type JourneyStats ¶
type JourneyStats struct {
Started uint64 `json:"started"`
Completed uint64 `json:"completed"`
Failed uint64 `json:"failed"`
Duration *Histogram `json:"duration"`
}
JourneyStats aggregates whole iterations of a journey.
type Percentiles ¶
type Percentiles struct {
Count uint64 `json:"count"`
Min float64 `json:"min"`
Mean float64 `json:"mean"`
P50 float64 `json:"p50"`
P90 float64 `json:"p90"`
P95 float64 `json:"p95"`
P99 float64 `json:"p99"`
P999 float64 `json:"p999"`
Max float64 `json:"max"`
}
Percentiles is a fixed summary of a histogram, in seconds.
type Phase ¶
type Phase int
Phase indexes per-request timing phases.
const ( PhaseDNS Phase = iota PhaseConnect PhaseTLS PhaseWait // time to first byte after the request was written PhaseDownload // PhaseFirstEvent is the time from the start of a streaming step to // its first event: time to first token for an LLM API. PhaseFirstEvent // Browser page loads: first contentful paint, largest contentful // paint, cumulative layout shift, interaction to next paint and the // load event, each from the start of the navigation or interaction. // CLS is unitless; it is stored as CLS seconds (a shift of 0.1 is // recorded as 100ms) so it fits the same histograms. PhaseFCP PhaseLCP PhaseCLS PhaseINP PhaseLoad NumPhases )
Request phases, as measured by net/http/httptrace, plus the time to the first event of a stream (server-sent events, gRPC server streaming). New phases are only ever appended: workers and servers exchange phases by index, and a peer that knows fewer phases leaves the rest empty.
type Sample ¶
type Sample struct {
Step int
// Intended is when the request should have been sent. In open-model
// runs a late dispatch makes it earlier than Start; latency is
// measured from here to avoid coordinated omission.
Intended time.Time
Start time.Time
End time.Time
Phases [NumPhases]time.Duration
Status int
// Err is an error class ("" for success at the transport level).
Err string
Failed bool
ChecksPassed int
ChecksFailed int
BytesIn int64
BytesOut int64
// Proto is the negotiated protocol, such as "HTTP/1.1" or "HTTP/2.0".
Proto string
// Events counts the events or messages a streaming step received;
// StreamTime is the time from the first of them to the end of the step.
Events int
StreamTime time.Duration
// TraceID is the W3C trace ID sent with the request (all zero when
// none was sent).
TraceID [16]byte
// Exchange, set on some failed samples, is an example of the failure
// for the report (see MaxErrorExamples).
Exchange *ErrorExample
}
Sample is one completed request.
type SlowRequest ¶
type SlowRequest struct {
// Latency is measured from the intended send time, like StepStats.Latency.
Latency time.Duration `json:"latency"`
// Start is when the request was sent.
Start time.Time `json:"start"`
// TraceID is the 32-hex-digit W3C trace ID, empty when none was sent.
TraceID string `json:"traceId,omitempty"`
Status int `json:"status,omitempty"`
Err string `json:"error,omitempty"`
}
SlowRequest is one of the slowest requests of a step.
type Snapshot ¶
type Snapshot struct {
// Interval is the number of whole intervals since the run's T0.
Interval int64 `json:"interval"`
// Seq increases by one per snapshot from a worker so resends are
// detected and never counted twice.
Seq uint64 `json:"seq,omitempty"`
Worker string `json:"worker,omitempty"`
Steps map[int]*StepStats `json:"steps,omitempty"`
Journeys map[int]*JourneyStats `json:"journeys,omitempty"`
// Dropped counts open-model iterations that could not start because
// no virtual user was free.
Dropped uint64 `json:"dropped,omitempty"`
// SchedLag is how late iterations were dispatched versus schedule.
SchedLag *Histogram `json:"schedLag,omitempty"`
// VUs is the number of active virtual users at the end of the interval.
VUs int `json:"vus"`
// Planned is the planned load (users or rate) at the interval.
Planned float64 `json:"planned,omitempty"`
}
Snapshot holds everything recorded during one interval (normally one second) by one worker, or the merge of many.
func NewSnapshot ¶
NewSnapshot returns an empty snapshot for an interval.
func (*Snapshot) Journey ¶
func (s *Snapshot) Journey(id int) *JourneyStats
Journey returns the stats for a journey, creating them when absent.
func (*Snapshot) Merge ¶
Merge adds every count and histogram in o into s. Gauges (VUs) are summed, which is right when merging different workers for the same interval.
type StepStats ¶
type StepStats struct {
Requests uint64 `json:"requests"`
Failed uint64 `json:"failed"`
Errors map[string]uint64 `json:"errors,omitempty"`
Status map[int]uint64 `json:"status,omitempty"`
ChecksPassed uint64 `json:"checksPassed,omitempty"`
ChecksFailed uint64 `json:"checksFailed,omitempty"`
BytesIn uint64 `json:"bytesIn"`
BytesOut uint64 `json:"bytesOut"`
// Latency is measured from the intended send time.
Latency *Histogram `json:"latency"`
// Service is measured from the actual send time.
Service *Histogram `json:"service"`
// PhaseSum holds per-phase totals in µs for computing means.
PhaseSum [NumPhases]uint64 `json:"phaseSum"`
// Streams counts samples that received at least one stream event,
// Events the events they received and StreamUs the µs from each
// stream's first event to its end. Events per second after the first
// event is (Events - Streams) / StreamUs.
Streams uint64 `json:"streams,omitempty"`
Events uint64 `json:"events,omitempty"`
StreamUs uint64 `json:"streamUs,omitempty"`
// Protocols counts requests by negotiated protocol (HTTP/1.1, HTTP/2.0).
Protocols map[string]uint64 `json:"protocols,omitempty"`
// Slowest holds up to MaxSlowest of the slowest requests, slowest
// first, with their trace IDs.
Slowest []SlowRequest `json:"slowest,omitempty"`
// Examples holds up to MaxErrorExamples failed requests per error.
Examples map[string][]ErrorExample `json:"examples,omitempty"`
}
StepStats aggregates one request step.