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

treeprobe

package
v1.3.104 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package treeprobe pkg/util/treeprobe/aggregate.go c0-com-util

Package treeprobe pkg/util/treeprobe/csv.go c0-com-util

Package treeprobe pkg/util/treeprobe/event.go c0-com-util `cli visor ping tree-stream`, aggregates ping/latency/jitter metrics per (level, parent_pk, remote_pk) tuple, joins against TPD's per-transport bandwidth + latency snapshot, and emits a CSV row per cell of the hop × routes measurement matrix.

The package is a thin consumer — it does not invoke `cli ping tree-stream` itself; the driver (ci_scripts/tree-probe.sh) is responsible for spawning the CLI with the right --hops flags and piping the NDJSON into the treeprobe binary on stdin.

Wire envelope (locked in PR #2732):

{"ts": "2026-05-20T01:30:00.123Z",
 "type": "ping_result",
 "data": { ...proto-snake_case fields, int64 as string... }}

The outer envelope uses RFC3339Nano timestamps and one of 6 discriminator strings. The inner data is protojson-marshaled from the corresponding PingTree* proto message with UseProtoNames=true (snake_case fields) and the protobuf int64 → JSON string convention. Numeric duration/byte fields in this package's mirror types are typed as Int64String to surface that quirk explicitly to consumers.

Package treeprobe pkg/util/treeprobe/parser.go c0-com-util

Index

Constants

This section is empty.

Variables

View Source
var CSVHeaders = []string{

	"level",
	"parent_pk",
	"remote_pk",

	"tp_id",
	"tp_type",

	"latency_source",
	"failed",
	"canceled",
	"sample_count",

	"setup_latency_ms",
	"ping_avg_ms",
	"ping_p50_ms",
	"ping_p99_ms",
	"jitter_ms",

	"setup_err",
	"ping_err",
	"calc_err",

	"route_hops",

	"run_total_discovered",
	"run_total_pinged",
	"run_total_succeeded",
	"run_total_failed",
	"run_total_skipped_cached",
	"run_wall_time_ms",
	"run_peak_in_flight",
	"run_termination_reason",
	"run_cache_hit_rate",
}

Column headers. Order is the CSV write order; downstream parsers should index by header name not position to remain stable across future column additions.

Functions

func WriteCSV

func WriteCSV(w io.Writer, a *Aggregator) (int, error)

WriteCSV emits the aggregator's cells as CSV rows to w. Returns the number of rows written + any write error.

Types

type Aggregator

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

Aggregator collects Decoded events into a per-cell map + tracks level-and-run totals. Safe for single-goroutine use only — the harness feeds it from one parser loop.

func NewAggregator

func NewAggregator() *Aggregator

NewAggregator constructs an empty Aggregator.

func (*Aggregator) CacheHitRate

func (a *Aggregator) CacheHitRate() float64

CacheHitRate returns the fraction of total_skipped_cached over (total_pinged + total_skipped_cached) — the cache hit rate from PR #2733's use_transport_latency fast-path. Returns 0 if RunDone is missing or denominator is zero.

func (*Aggregator) Cells

func (a *Aggregator) Cells() []*Cell

Cells returns the per-cell entries sorted deterministically by (Level asc, ParentPK asc, RemotePK asc) so CSV rows stay stable across runs of the same input.

func (*Aggregator) Levels

func (a *Aggregator) Levels() []*LevelDone

Levels returns the per-level summaries in ascending level order.

func (*Aggregator) Observe

func (a *Aggregator) Observe(d *Decoded)

Observe folds one Decoded event into the aggregator's state. Returns silently on unknown event-types — Parser.Next already validates the discriminator, so unknowns shouldn't reach here.

func (*Aggregator) RunDone

func (a *Aggregator) RunDone() *RunDone

RunDone returns the final RunDone event, or nil if the stream ended before run_done fired (i.e., truncated capture).

func (*Aggregator) ServerError

func (a *Aggregator) ServerError() *ServerError

ServerError returns the terminal ServerError, or nil if the run ended cleanly.

func (*Aggregator) StatusUpdateCount

func (a *Aggregator) StatusUpdateCount() int

StatusUpdateCount returns the count of status_update events observed. Useful for harness diagnostics — not normally surfaced to CSV.

type Cell

type Cell struct {
	Key        CellKey
	Discovered *Discovered
	Result     *PingResult
}

Cell is one (level, parent, remote) entry's collected state. Result is the canonical metric carrier from the server; Discovered is set if a `discovered` event preceded the result (always true in well-formed streams).

type CellKey

type CellKey struct {
	Level    int32
	ParentPK string
	RemotePK string
}

CellKey identifies one (level, parent_pk, remote_pk) tuple. Used as a map key on the aggregator + as the CSV row identity.

type Decoded

type Decoded struct {
	TS   string
	Type EventType

	Discovered   *Discovered
	PingResult   *PingResult
	LevelDone    *LevelDone
	RunDone      *RunDone
	StatusUpdate *StatusUpdate
	ServerError  *ServerError
}

Decoded is the parser's emit shape. Exactly one of the *Payload fields is non-nil per Decoded, matching Envelope.Type. The TS field is the RFC3339Nano timestamp string from the envelope — callers convert to time.Time on demand.

type Discovered

type Discovered struct {
	TpID     string `json:"tp_id"`
	TpType   string `json:"tp_type"`
	RemotePK string `json:"remote_pk"`
	ParentPK string `json:"parent_pk"`
	Level    int32  `json:"level"`
}

Discovered fires when the BFS first observes a new (transport, remote_pk) pair, before any ping is attempted.

type Envelope

type Envelope struct {
	TS   string          `json:"ts"`
	Type EventType       `json:"type"`
	Data json.RawMessage `json:"data"`
}

Envelope is the outer NDJSON line shape. Data is held as json.RawMessage so the consumer can defer decoding to the type-specific struct once it has Type in hand.

type EventType

type EventType string

EventType is the discriminator string in the envelope's "type" field. Mirrors the classifyPayload switch in cmd/skywire-cli/commands/visor/ping/tree_stream.go.

const (
	TypeDiscovered   EventType = "discovered"
	TypePingResult   EventType = "ping_result"
	TypeLevelDone    EventType = "level_done"
	TypeRunDone      EventType = "run_done"
	TypeStatusUpdate EventType = "status_update"
	TypeServerError  EventType = "server_error"
)

type Int64String

type Int64String int64

Int64String is the JSON shape protobuf uses for int64 fields: always a JSON string. Wrapping it in a named type lets the parser surface the convention to consumers + lets us add convenience methods for nanosecond → time.Duration conversion without polluting every struct field.

func (Int64String) MarshalJSON

func (i Int64String) MarshalJSON() ([]byte, error)

MarshalJSON emits the int64-as-string form on the way out — useful for round-tripping in tests + keeps the on-the-wire shape stable.

func (*Int64String) UnmarshalJSON

func (i *Int64String) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes either a JSON string (protobuf default) OR a JSON number (tolerant for hand-written test fixtures). Returns an error on any non-integer value.

type LevelDone

type LevelDone struct {
	Level         int32 `json:"level"`
	Attempted     int32 `json:"attempted"`
	Succeeded     int32 `json:"succeeded"`
	Failed        int32 `json:"failed"`
	SkippedCached int32 `json:"skipped_cached"`
}

LevelDone fires when the BFS finishes all peers at a given level. SkippedCached is non-zero when transport_summary fast-path short-circuited some peers (Beta's PR #2733). Lets the harness compute use_transport_latency hit-rate per level.

type Parser

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

Parser wraps a bufio.Scanner over an NDJSON stream from `cli visor ping tree-stream`. Use NewParser to construct, then Next() in a loop until io.EOF.

func NewParser

func NewParser(r io.Reader) *Parser

NewParser constructs a Parser over r. Uses a 1 MiB scan buffer because PingResult events with long route arrays + error messages can run several KiB; default bufio buffer (64 KiB) would suffice today but bumping is cheap insurance against future field bloat.

func (*Parser) Next

func (p *Parser) Next() (*Decoded, error)

Next returns the next decoded event, io.EOF when the stream is exhausted, or a non-nil error on parse failure. Blank lines + trailing whitespace are skipped. Unknown Type values yield an error rather than silent skip — the spec is closed at 6 event types and a new one shouldn't sneak past us undetected.

type PingResult

type PingResult struct {
	TpID     string `json:"tp_id"`
	TpType   string `json:"tp_type"`
	RemotePK string `json:"remote_pk"`
	ParentPK string `json:"parent_pk"`
	Level    int32  `json:"level"`
	// Proto field name is "canceled" (en-US per misspell linter,
	// renamed from initial pre-review spelling during 2026-05-20
	// design review).
	Canceled bool `json:"canceled"`

	SampleCount  int32       `json:"sample_count"`
	SetupLatency Int64String `json:"setup_latency_ns"`
	PingAvgNs    Int64String `json:"ping_avg_ns"`
	PingP50Ns    Int64String `json:"ping_p50_ns"`
	PingP99Ns    Int64String `json:"ping_p99_ns"`
	// JitterNs is population stddev of ping samples:
	// sqrt(sum((x-mean)^2) / N). Spec'd 2026-05-20 00:54Z.
	JitterNs Int64String `json:"jitter_ns"`

	Failed   bool   `json:"failed"`
	SetupErr string `json:"setup_err,omitempty"`
	PingErr  string `json:"ping_err,omitempty"`
	CalcErr  string `json:"calc_err,omitempty"`

	// LatencySource is one of:
	//   "live_ping"          — fresh measurement
	//   "transport_summary"  — smoothed RTT from TransportSummary.LatencyMS
	//                          (PR #2733, level-1 only)
	//   "skipped"            — cached fast-path explicitly disabled
	LatencySource string     `json:"latency_source"`
	Route         []RouteHop `json:"route,omitempty"`
}

PingResult is the canonical measurement event. One per peer in the tree, regardless of whether the latency was sampled live or pulled from the cached TransportSummary. LatencySource discriminates the provenance.

Wire-NOT-deterministic ordering: results arrive interleaved by completion, not in BFS traversal order. The harness sorts/groups by (Level, ParentPK, RemotePK) on receive.

type RouteHop

type RouteHop struct {
	TpID     string `json:"tp_id"`
	TpType   string `json:"tp_type"`
	RemotePK string `json:"remote_pk"`
}

RouteHop is one entry in the route taken from probe origin to the target peer. PingResult.Route is empty for level-1 entries.

type RunDone

type RunDone struct {
	TotalDiscovered    int32       `json:"total_discovered,omitempty"`
	TotalPinged        int32       `json:"total_pinged,omitempty"`
	TotalSucceeded     int32       `json:"total_succeeded,omitempty"`
	TotalFailed        int32       `json:"total_failed,omitempty"`
	TotalSkippedCached int32       `json:"total_skipped_cached,omitempty"`
	WallTimeNs         Int64String `json:"wall_time_ns"`
	PeakInFlight       int32       `json:"peak_in_flight,omitempty"`
	TerminationReason  string      `json:"termination_reason,omitempty"`
}

RunDone fires once at the end of a successful (or canceled) run. Field names match PingTreeRunDone in pkg/visor/rpcgrpc/ping.pb.go; most fields are int32 counters, WallTimeNs is the protobuf int64 → JSON string convention.

TerminationReason is one of:

"max_level"      — hit cfg.MaxLevel
"no_neighbors"   — BFS exhausted before MaxLevel
"hops_target"    — reached cfg.Hops target level
"context_cancel" — client disconnect / server shutdown
"error"          — see ServerError preceding this event

type ServerError

type ServerError struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ServerError is emitted when the BFS handler hits a fatal error it can't recover from. Always the last event before the stream terminates.

type StatusUpdate

type StatusUpdate struct {
	Phase    string `json:"phase"`
	InFlight int32  `json:"in_flight"`
	Pending  int32  `json:"pending"`
}

StatusUpdate fires periodically (cadence server-chosen) to surface live in-flight + queue state. Dropped first under back- pressure on the bounded event channel.

Jump to

Keyboard shortcuts

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