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

dashspec

package
v1.0.2 Latest Latest
Warning

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

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

Documentation

Overview

Package dashspec is forge's renderer-neutral dashboard vocabulary (forge.dashboards/v1) and its validator: the types a dashboard file is written in, and ParseDashboard, which judges one with every problem located by line, column and path.

forge generates dashboards in this vocabulary (deploy/observability/), a release bundle carries them, and the Reliant control plane saves and promotes them. Every one of those reads the same rules from here, so a dashboard forge writes is one every reader accepts, and a new panel kind reaches all of them with one forge pin bump instead of one hand-kept copy per reader.

Fields are OpenTelemetry names keyed by signal (see CheckField); nothing here names a ClickHouse column, a HyperDX field or a chart library.

Index

Constants

View Source
const (
	// MaxLimit is the most rows a panel may keep.
	MaxLimit = 200
	// DefaultBarLimit is how many bar groups a bar panel with no Limit draws.
	DefaultBarLimit = 10
)

Row limits of a table or bar panel (Panel.Limit).

View Source
const (
	DefaultFunnelWindow = "1h"
	DefaultFunnelBy     = FunnelBySession
)

Funnel defaults, applied where a panel leaves a field empty.

View Source
const (
	FieldService = "service.name"
	FieldEnv     = "deployment.environment.name"
)

Semantic field names. A field is one of:

service.name, deployment.environment.name        (every signal)
span.name, span.kind, span.status,
span.status_message, span.duration               (traces)
span.attr.<key>                                  (traces)
log.severity, log.body, log.attr.<key>           (logs)
metric.attr.<key>                                (metrics)
resource.attr.<key>                              (every signal)

span.kind is "server" or "client"; span.status and log.severity compare against "error". span.duration is milliseconds.

View Source
const (
	// SQLParamFrom is the start of the dashboard's time range, inclusive:
	// {from:DateTime64(9)}.
	SQLParamFrom = "from"
	// SQLParamTo is the end of the dashboard's time range, exclusive:
	// {to:DateTime64(9)}.
	SQLParamTo = "to"
	// SQLParamStep is a bucket width in seconds suited to the range, for a
	// time series: {step:UInt32}.
	SQLParamStep = "step"
	// SQLParamEnvIDs are the reliant.env.id values in scope; empty means every
	// environment: {env_ids:Array(String)}.
	SQLParamEnvIDs = "env_ids"
	// SQLParamEnvs are the deployment.environment.name values in scope, in the
	// order of SQLParamEnvIDs: {envs:Array(String)}.
	SQLParamEnvs = "envs"
	// SQLParamServices are the service.name values in scope; empty means
	// every service: {services:Array(String)}.
	SQLParamServices = "services"
)

The query parameters a KindSQL panel's statement may use. They are ClickHouse's native parameters, written {name:Type} in the statement and bound by the server from the dashboard's scope: nothing a viewer picks is ever spliced into the SQL. A statement need not use any of them, and may use each any number of times.

SELECT toStartOfInterval(Timestamp, toIntervalSecond({step:UInt32})) AS t,
       count() AS requests
FROM otel_traces
WHERE Timestamp >= {from:DateTime64(9)} AND Timestamp < {to:DateTime64(9)}
  AND (empty({services:Array(String)}) OR has({services:Array(String)}, ServiceName))
GROUP BY t ORDER BY t
View Source
const GridColumns = 24

GridColumns is the width of a dashboard's grid: a panel's Width is in columns out of it.

View Source
const MaxFormulaLen = 256

MaxFormulaLen bounds a panel's Formula.

View Source
const MaxSQLBytes = alerting.MaxExprBytes

MaxSQLBytes bounds a KindSQL panel's statement: an alert rule's expr bound, because the two run under the same guard.

View Source
const SpecVersion = "forge.dashboards/v1"

SpecVersion identifies the serialized shape of Spec. Bump it on a breaking change so a consumer can refuse a spec it does not understand.

Variables

This section is empty.

Functions

func CheckField

func CheckField(sig Signal, field string) error

CheckField reports whether field is a semantic field on signal (the vocabulary documented on FieldService). Every renderer maps exactly these fields, so a field CheckField accepts is one each can draw.

func CheckSQL

func CheckSQL(sql string) error

CheckSQL reports whether sql is a statement a KindSQL panel may carry: non-empty, at most MaxSQLBytes, and exactly one read-only SELECT by the alert rule guard (alerting.ValidateExpr), which refuses writes, DDL, SETTINGS, FORMAT, the system database and the table functions that read outside the owner's data.

It is the first line of defence, not the containment: a reader must run the statement as a read-only database user confined to the viewer's own data, under a timeout and a row cap, exactly as it runs an alert rule.

func IsConsoleKind

func IsConsoleKind(k PanelKind) bool

IsConsoleKind reports whether k is drawn only by the Reliant console, so the HyperDX renderer has nothing to emit for it.

func LooksLikeHyperDXDashboard

func LooksLikeHyperDXDashboard(raw []byte) bool

LooksLikeHyperDXDashboard reports whether raw is a HyperDX v2 dashboard.

func LooksLikeSpecDashboard

func LooksLikeSpecDashboard(raw []byte) bool

LooksLikeSpecDashboard reports whether raw is a spec-form dashboard rather than a HyperDX one: it has a "panels" array and no "tiles".

func SeriesRef

func SeriesRef(i int) string

SeriesRef is the name a Formula gives Series[i]: A for the first, B for the second, up to J for the tenth.

Types

type Agg

type Agg string

Agg is an aggregate function.

const (
	AggCount         Agg = "count"
	AggCountDistinct Agg = "count_distinct"
	AggSum           Agg = "sum"
	AggAvg           Agg = "avg"
	AggMax           Agg = "max"
	AggQuantile      Agg = "quantile"
	AggLast          Agg = "last"
	// AggRate, AggIncrease and AggMin are metrics-only. A rate is per second,
	// an increase is per bucket, and both are time-weighted per series; on a
	// monotonic sum, AggSum still means the increase.
	AggRate     Agg = "rate"
	AggIncrease Agg = "increase"
	AggMin      Agg = "min"
)

The aggregate functions a series can apply.

type Annotation

type Annotation struct {
	Source AnnotationSource `json:"source"`
	Label  string           `json:"label,omitempty"`
}

Annotation is a marker series drawn over every KindLine panel of a dashboard. HyperDX has no such concept, so RenderHyperDX ignores it.

type AnnotationSource

type AnnotationSource string

AnnotationSource names where a dashboard's time-series markers come from.

const (
	// AnnotationReleases marks every promotion of a release into the
	// environment on the dashboard's time-series panels.
	AnnotationReleases AnnotationSource = "releases"
)

The annotation sources. The spec only DECLARES a source; the renderer draws it from data it owns (the Reliant console reads the release ledger).

type Dashboard

type Dashboard struct {
	Sections    []Section    `json:"sections,omitempty"`
	ID          string       `json:"id"`
	Title       string       `json:"title"`
	Description string       `json:"description,omitempty"`
	Filters     []Filter     `json:"filters,omitempty"`
	Annotations []Annotation `json:"annotations,omitempty"`
	Panels      []Panel      `json:"panels"`
}

Dashboard is an ordered list of panels under a shared set of filters.

func ParseDashboard

func ParseDashboard(name string, raw []byte) (Dashboard, error)

ParseDashboard decodes and validates one dashboard file: a single Dashboard object in the renderer-neutral spec vocabulary (the objects of the spec's dashboards). name is only used in errors.

Every problem found is reported, each with the line and column of the offending value (or, for an unknown field, of its key). Validation covers what the renderers and the console's query engine would otherwise discover one request at a time: field names that exist on the panel's signal, the operator set, series limits, a quantile's range, a metric series naming its metric and type, and unique ids.

type Filter

type Filter struct {
	// PanelIDs restricts this filter to declared panels. Empty preserves the
	// dashboard-wide default. RPC filters must not blank runtime/billing panels.
	PanelIDs []string `json:"panelIds,omitempty"`
	ID       string   `json:"id"`
	Label    string   `json:"label"`
	Field    string   `json:"field"`
	// Signal is the telemetry the dropdown reads its values from. Empty is
	// Traces, which every dashboard but the metrics ones draws.
	Signal Signal `json:"signal,omitempty"`
}

Filter is a dashboard-level dropdown that narrows every panel.

type Formula

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

Formula is a parsed Panel.Formula: arithmetic over a panel's series values. Every reader evaluates it with Eval, so a formula means the same thing in each.

func ParseFormula

func ParseFormula(expr string, series int) (*Formula, error)

ParseFormula parses expr against a panel with series series.

The grammar is the four operators over series references and numbers:

expr    = term { ("+" | "-") term }
term    = unary { ("*" | "/") unary }
unary   = "-" unary | primary
primary = number | ref | "(" expr ")"

A ref is one capital letter naming a series by position (SeriesRef); a number is decimal, with an optional fraction and exponent. A formula must reference at least one series, and at most MaxFormulaLen bytes long.

func (*Formula) Eval

func (f *Formula) Eval(vals []float64) float64

Eval computes the formula with vals[i] as Series[i]'s value. Division by zero yields 0, as a ratio of a zero denominator does, and so does any other result that is not a finite number: a reader draws it as zero rather than as a gap or an error.

func (*Formula) EvalNullable added in v1.0.0

func (f *Formula) EvalNullable(vals []float64, present []bool) (float64, bool)

EvalNullable computes the formula where a series' value may be absent: present[i] says whether vals[i] exists. Absence propagates (an expression with an absent operand is absent), a division by zero is absent, and so is any non-finite result. A reader draws an absent result as a gap, which is what a gauge ratio wants where Eval's 0 would be a lie.

func (*Formula) Refs

func (f *Formula) Refs() []int

Refs are the indexes of the series the formula reads, ascending.

func (*Formula) String

func (f *Formula) String() string

String is the formula's canonical spelling: single spaces around binary operators and only the parentheses its precedence needs.

type Funnel

type Funnel struct {
	// Steps are product event names (the names passed to track()), in order.
	Steps []string `json:"steps"`
	// Window is how long a journey may take from its first step to its last:
	// a number and a unit of s, m, h or d ("1h", "7d"). Empty is "1h".
	Window string `json:"window,omitempty"`
	// By is the journey's identity. Empty is FunnelBySession.
	By FunnelBy `json:"by,omitempty"`
}

Funnel is the definition a KindFunnel panel draws: the ordered event names a journey passes through, within Window, counted per session or per user.

type FunnelBy

type FunnelBy string

FunnelBy is what a funnel counts: how events are tied into one journey.

const (
	FunnelBySession FunnelBy = "session"
	FunnelByUser    FunnelBy = "user"
)

The funnel journeys.

type Op

type Op string

Op is a predicate operator.

const (
	OpEq     Op = "eq"
	OpNeq    Op = "neq"
	OpIn     Op = "in"
	OpNotIn  Op = "not_in"
	OpPrefix Op = "prefix"
	OpMatch  Op = "match" // RE2
	OpExists Op = "exists"
	OpGTE    Op = "gte"
)

The predicate operators.

type Panel

type Panel struct {
	// Section is an optional declared dashboard section, for temporary viewer
	// toggles. Empty retains the unsectioned layout.
	Section     string    `json:"section,omitempty"`
	ID          string    `json:"id"`
	Title       string    `json:"title"`
	Description string    `json:"description,omitempty"`
	Kind        PanelKind `json:"kind"`
	// Signal is required on every kind but KindSQL, whose statement names its
	// own tables.
	Signal Signal   `json:"signal,omitempty"`
	Series []Series `json:"series,omitempty"`
	// Ratio makes a two-series line panel plot Series[0]/Series[1]
	// (an error rate is failed requests over all requests).
	Ratio bool `json:"ratio,omitempty"`
	// Formula makes a line or number panel plot one arithmetic expression
	// over its series instead of the series themselves: "A / B * 100", where
	// A is Series[0], B is Series[1], and so on (see ParseFormula). It is the
	// general form of Ratio, which a panel uses instead of, not with, it.
	Formula string `json:"formula,omitempty"`
	// Limit keeps the top Limit rows of a table or bar panel, largest
	// Series[0] first. Zero is DefaultBarLimit for a bar and the reader's own
	// row cap for a table; at most MaxLimit.
	Limit int `json:"limit,omitempty"`
	// SQL is a KindSQL panel's statement: one read-only SELECT over the
	// telemetry tables, which may use the SQLParam* query parameters. Only
	// that kind takes it.
	SQL string `json:"sql,omitempty"`
	// Where narrows every series of the panel.
	Where   []Predicate `json:"where,omitempty"`
	GroupBy []string    `json:"groupBy,omitempty"`
	// Columns are the fields a KindSearch panel shows.
	Columns []string `json:"columns,omitempty"`
	// Funnel is what a KindFunnel panel draws; only that kind takes it.
	Funnel *Funnel `json:"funnel,omitempty"`
	// HasError narrows a KindSessions panel to sessions that hit an error;
	// only that kind takes it.
	HasError bool `json:"hasError,omitempty"`
	Unit     Unit `json:"unit,omitempty"`
	// Width is in grid columns out of 24; Height in rows. Zero takes the
	// default for the kind.
	Width  int `json:"width,omitempty"`
	Height int `json:"height,omitempty"`
}

Panel is one tile.

type PanelKind

type PanelKind string

PanelKind is how a panel is drawn.

const (
	// KindNumber is one headline value over the selected time range.
	KindNumber PanelKind = "number"
	// KindLine is a time series; with GroupBy, one line per group.
	KindLine PanelKind = "line"
	// KindTable is one row per GroupBy value, one column per Series.
	KindTable PanelKind = "table"
	// KindSearch is a log or span search (no aggregate): the rows themselves.
	KindSearch PanelKind = "search"
	// KindBar is a top-N bar chart: one bar group per GroupBy value, one bar
	// per Series within it, the Limit groups with the largest Series[0] first.
	KindBar PanelKind = "bar"
	// KindHeatmap is the distribution of one numeric field over time: time
	// buckets across, value buckets up, each cell coloured by how many events
	// fell in it (a latency heatmap is span.duration). It takes exactly one
	// series, a count with the bucketed value in Field.
	KindHeatmap PanelKind = "heatmap"
	// KindSQL is drawn from a read-only ClickHouse SELECT the panel carries in
	// SQL instead of from series. The reader runs it with the same guard and
	// limits as an alert rule's expr (see CheckSQL and the SQLParam*
	// parameters).
	KindSQL PanelKind = "sql"

	// KindIssues is the grouped-errors list: new and regressed issues first,
	// then the most frequent. Served by RumService ListIssues.
	KindIssues PanelKind = "issues"
	// KindSessions is a list of browser sessions, with replay links. Served by
	// RumService ListSessions; HasError narrows it to sessions with an error.
	KindSessions PanelKind = "sessions"
	// KindFunnel is a product-event funnel over Panel.Funnel. Served from the
	// product_events table with ClickHouse windowFunnel.
	KindFunnel PanelKind = "funnel"
)

type Predicate

type Predicate struct {
	Field  string   `json:"field"`
	Op     Op       `json:"op"`
	Value  string   `json:"value,omitempty"`
	Values []string `json:"values,omitempty"`
}

Predicate is one condition. Values are literals; Field is a semantic field.

type Problem

type Problem struct {
	// Line and Col are 1-based; zero when the position is unknown.
	Line, Col int
	// Path is where in the document: panels[2].series[0].agg.
	Path    string
	Message string
}

Problem is one thing wrong with a dashboard file, located in it.

func ProblemsOf

func ProblemsOf(err error) []Problem

ProblemsOf returns the problems a ParseDashboard error carries, or nil for an error that is not one.

type Section added in v1.0.0

type Section struct {
	ID    string `json:"id"`
	Title string `json:"title"`
}

Section is a named, ordered group of panels. It changes presentation only; filtering remains explicit through Filter.PanelIDs.

type Series

type Series struct {
	Label string `json:"label"`
	Agg   Agg    `json:"agg"`
	// Quantile is the level for AggQuantile, e.g. 0.95.
	Quantile float64 `json:"quantile,omitempty"`
	// Field is the aggregated value: a semantic field for traces and logs
	// (span.duration, span.attr.lcp), the metric NAME for metrics. Empty for
	// AggCount.
	Field string `json:"field,omitempty"`
	// MetricType is "sum", "gauge", "histogram", "exp_histogram" or "summary"
	// (metrics only).
	MetricType string `json:"metricType,omitempty"`
	// Where narrows this series alone (e.g. only the failed requests).
	Where []Predicate `json:"where,omitempty"`
	// Thresholds grade the series' values good / needs improvement / poor.
	Thresholds *Thresholds `json:"thresholds,omitempty"`
}

Series is one aggregate shown by a panel.

type Signal

type Signal string

Signal is the telemetry table a panel reads.

const (
	Traces  Signal = "traces"
	Metrics Signal = "metrics"
	Logs    Signal = "logs"
)

The signals a panel can read.

type Thresholds

type Thresholds struct {
	Good float64 `json:"good"`
	Poor float64 `json:"poor"`
}

Thresholds colour a series' values the way Core Web Vitals do: at or below Good is good, above Poor is poor, between is "needs improvement". Renderers that cannot colour ignore it.

type Unit

type Unit string

Unit is how a panel's values are formatted.

const (
	UnitNone    Unit = ""
	UnitCount   Unit = "count"
	UnitMillis  Unit = "ms"
	UnitBytes   Unit = "bytes"
	UnitPercent Unit = "percent" // values are fractions in [0,1]
	UnitSeconds Unit = "s"
)

The units a panel's values are formatted in.

Jump to

Keyboard shortcuts

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