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
- func CheckField(sig Signal, field string) error
- func CheckSQL(sql string) error
- func IsConsoleKind(k PanelKind) bool
- func LooksLikeHyperDXDashboard(raw []byte) bool
- func LooksLikeSpecDashboard(raw []byte) bool
- func SeriesRef(i int) string
- type Agg
- type Annotation
- type AnnotationSource
- type Dashboard
- type Filter
- type Formula
- type Funnel
- type FunnelBy
- type Op
- type Panel
- type PanelKind
- type Predicate
- type Problem
- type Section
- type Series
- type Signal
- type Thresholds
- type Unit
Constants ¶
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).
const ( DefaultFunnelWindow = "1h" DefaultFunnelBy = FunnelBySession )
Funnel defaults, applied where a panel leaves a field empty.
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.
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
const GridColumns = 24
GridColumns is the width of a dashboard's grid: a panel's Width is in columns out of it.
const MaxFormulaLen = 256
MaxFormulaLen bounds a panel's Formula.
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.
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 ¶
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 ¶
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 ¶
IsConsoleKind reports whether k is drawn only by the Reliant console, so the HyperDX renderer has nothing to emit for it.
func LooksLikeHyperDXDashboard ¶
LooksLikeHyperDXDashboard reports whether raw is a HyperDX v2 dashboard.
func LooksLikeSpecDashboard ¶
LooksLikeSpecDashboard reports whether raw is a spec-form dashboard rather than a HyperDX one: it has a "panels" array and no "tiles".
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 ¶
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 ¶
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 ¶
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
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.
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.
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 ¶
ProblemsOf returns the problems a ParseDashboard error carries, or nil for an error that is not one.
type Section ¶ added in v1.0.0
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 Thresholds ¶
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.