CollabOps

Definition JSON reference

Every field of the dashboard definition document, and the rules that validate it

A dashboard definition is one JSON document. This page is its syntax — which fields exist and what gets rejected.

The editor, the create API, import, and repository sync all go through the same validator, so the rules here hold whichever path you use. The import screen runs the same validation before saving, so a hand-written document can simply be pasted there to check it.

Minimal example

One panel plotting request count per service over time.

{
  "schemaVersion": 1,
  "panels": [
    {
      "id": "throughput",
      "title": "Throughput",
      "layout": { "x": 0, "y": 0, "w": 6, "h": 6 },
      "visualization": { "type": "TIME_SERIES" },
      "queries": [
        {
          "refId": "A",
          "signal": "traces",
          "aggregation": { "function": "COUNT" },
          "groupBy": ["service.name"],
          "output": { "type": "TIME_SERIES" }
        }
      ]
    }
  ]
}

variables, sections, and settings may be omitted — the server fills in empty arrays and defaults and stores the normalized document.

Top level

FieldTypeRequiredDescription
schemaVersionintegeryesDefinition format version. Only 1 is understood today.
variablesarraynoValues picked at the top of the screen. Defaults to []
sectionsarraynoGroups of panels. Defaults to []
panelsarraynoThe tiles. Defaults to []
settingsobjectnoDefault time range, refresh interval, timezone
uidstringnoIdentifier that survives moving the document. Generated if absent.

If schemaVersion is not 1, the response is a single UNSUPPORTED_SCHEMA_VERSION and nothing below it is inspected — an unknown format gives no basis for reading the rest.

settings

FieldAllowed valuesDefault
defaultTimeRangeLAST_30_MIN · LAST_1_HOUR · LAST_6_HOURS · LAST_24_HOURS · LAST_7_DAYSLAST_1_HOUR
refreshIntervalNONE · 10s · 30s · 1m · 5m30s
timezoneBROWSER · UTCBROWSER

The execute API takes absolute timestamps (from, to). defaultTimeRange is what the screen selects when the dashboard is first opened.

variables

FieldTypeDescription
namestringRequired, unique within the definition. Filters reference it as ${name}.
labelstringName shown on screen
typestringSERVICE · ATTRIBUTE · TEXT · CUSTOM
sourceobjectATTRIBUTE only — signal and field, plus metric for metrics
defaultValuestring or arrayUsed when the request carries no selection
multibooleanAllow selecting several values
optionsstring arrayCUSTOM only — the fixed choices

Rules per type

TypeWhere values come fromRules
SERVICEThe workspace service catalogNo source needed.
ATTRIBUTEAttribute values actually collectedsource.signal and source.field are required. When signal is metrics, source.metric is required too — labels are read per metric.
TEXTNone (typed in)Cannot carry source or options.
CUSTOMoptionsNeeds at least one option and cannot carry source.

How a selection reaches a filter

{
  "variables": [
    { "name": "service", "label": "Service",     "type": "SERVICE", "defaultValue": "ALL", "multi": true },
    { "name": "env",     "label": "Environment", "type": "ATTRIBUTE",
      "source": { "signal": "traces", "field": "environment" } },
    { "name": "keyword", "label": "Search",      "type": "TEXT" },
    { "name": "tier",    "label": "Tier",        "type": "CUSTOM", "options": ["free", "pro"] }
  ],
  "panels": [
    {
      "id": "errors", "layout": { "x": 0, "y": 0, "w": 6, "h": 6 },
      "visualization": { "type": "TIME_SERIES" },
      "queries": [
        {
          "refId": "A", "signal": "traces",
          "aggregation": { "function": "COUNT" },
          "filters": [
            { "field": "service.name", "operator": "IN", "value": "${service}" },
            { "field": "has_error",    "operator": "EQ", "value": true }
          ],
          "groupBy": ["service.name"],
          "output": { "type": "TIME_SERIES" }
        }
      ]
    }
  ]
}
SituationResult
No selection in the requestdefaultValue is used.
The value is ALLFilters using that variable are dropped entirely — "all" means do not filter.
A multi variable with several valuesEven an EQ operator is promoted to IN; taking only the first value would quietly shrink the result.
Several values on a non-multi variableRejected.
An empty TEXT valueThat filter is dropped — nothing typed yet is a normal state.
An empty list selection (SERVICE, ATTRIBUTE, CUSTOM)Rejected — there was something to pick and nothing was picked.

The whole value must be the reference ${name}. Mixed forms such as prefix-${name} are rejected: string concatenation would strip the value of its type. Variable values must be strings — numbers and booleans are refused.

sections

FieldTypeDescription
idstringRequired, unique within the definition.
titlestringGroup heading
panelIdsstring arrayThe id of each panel in this section. Pointing at a missing panel is UNKNOWN_REFERENCE.

panels

FieldTypeDescription
idstringRequired, unique within the definition.
titlestringPanel heading
layoutobjectGrid position x, y, w, h
visualizationobjecttype plus optional options
queriesarrayRequired. Between 1 and 20.

layout

RuleDetail
Grid width12 columns; x + w above 12 is OUT_OF_RANGE
Sizew and h must be at least 1
Positionx and y cannot be negative
Height caph at most 24

visualization

The visualization does not decide the shape of the result. The query's output.type does, and validation only checks that the two are compatible.

visualization.typeRequired output.type
TIME_SERIESTIME_SERIES
NUMBERSCALAR
TABLE · BAR · PIE · LOGS · TRACESTABLE
HISTOGRAMHISTOGRAM

A mismatch is INCOMPATIBLE_OUTPUT. visualization.options is free-form JSON and is not validated.

queries

FieldTypeDescription
refIdstringRequired, unique within the panel. ratio points at this value.
signalstringtraces · logs · metrics. Not allowed on a ratio query.
sourceobjectThe metric name for a metrics query
aggregationobjectfunction, field, level
filtersarrayConditions, all combined with AND
groupBystring arrayAxes to split by. At most 5.
outputobjectRequired — type is the result shape.
aliasstringName given to the series or value column
recordsbooleanReturn raw rows instead of aggregating
measuresarrayValue columns of a table. At most 8.
ratioobjectDivide two queries of the same panel
limitintegerCap on series count; 0 means the default of 20, maximum 100
orderByobjectOrdering of raw records. Only allowed on a records query.

output.type

TypeShapeConditions
TIME_SERIEStime × seriesSeries come from groupBy.
SCALARone valueCannot have groupBy.
TABLErows × columnsNeeds at least one groupBy (except with records).
HISTOGRAMtime × bucketOnly metrics can produce it, and it cannot carry groupBy or aggregation.

When signal is metrics, source.metric is required — that field is the only place saying which metric is read.

filters

OperatorValueFields it works on
EQa single valueany field
INa non-empty arrayany field
CONTAINSa stringdictionary fields only (not attributes)
BETWEEN[min, max] — either side may be nulldictionary fields only (not attributes)
NOT_EQa single valueany field
NOT_INa non-empty arrayany field
NOT_CONTAINSa stringdictionary fields only (not attributes)

All filters in the list are combined with AND. There is no OR; choosing among several values is IN.

The negated operators exist so that "everything except this" can be written into the definition — slow requests excluding streaming ones, for instance, where working around it with a BETWEEN upper bound would throw away the genuinely slow requests too.

Attribute fields (the resource., span., log. prefixes and metric labels) accept EQ, IN, NOT_EQ, and NOT_IN. Substring matching (CONTAINS, NOT_CONTAINS) and ranges (BETWEEN) are not opened there because they cannot use the index. Values must be strings. The constraint is enforced at execution, not at save time — the definition saves and only the panel fails.

Field names

Field names resolve against a per-signal dictionary. A name that is not in it is rejected with UNKNOWN_FIELD, so that a typo cannot produce a dashboard that saves and then quietly fails to draw.

traces fieldMeaning
service.name · service.version · environmentService and deployment environment
trace_id · span_id · parent_span_idIdentifiers
name (= span_name)Span name
kindSpan kind
status_codeSpan status
has_errorError verdict, written as true / false
duration_msDuration in milliseconds — the field numeric aggregations use
logs fieldMeaning
service.name · service.version · environmentService and deployment environment
trace_id · span_idLinked trace
level (= severity)Severity, compared case-insensitively
bodyLog body
scope_name · event_nameScope and event that produced the line
metrics fieldMeaning
service.name · service.version · environmentService and deployment environment
metricMetric name
any other nameRead as a metric label — no dictionary entry needed

Attributes outside the dictionary are reached through prefixes.

PrefixSignalsPoints at
resource.traces · logs · metricsResource attributes — e.g. resource.k8s.pod.name
span.tracesSpan attributes — e.g. span.http.route
log.logsLog attributes — e.g. log.request_id

Only dictionary fields can be the argument of an aggregation (aggregation.field, measures[].field). Prefixed attributes are strings, so they cannot feed sum, average, or a quantile, and are rejected with UNKNOWN_FIELD. resource.workspace_id and resource.retention_days cannot be queried.

To see which fields and values actually arrived, use the filter on the Logs, Traces, and Metrics screens — whatever autocomplete offers is what a definition may use.

aggregation

SignalAvailable functions
traces · logsCOUNT SUM AVG MIN MAX UNIQ P50 P75 P90 P95 P99 QUANTILE
metricsCOUNT SUM AVG MIN MAX RATE INCREASE P50 P90 P95 P99
FieldDescription
functionA name from the table above. Lowercase is accepted and normalized to uppercase on save.
fieldThe field to aggregate. COUNT does not need one.
levelQUANTILE only. Must be strictly between 0 and 1 — e.g. 0.999

Which functions actually work on a metric depends on its type (gauge, sum, histogram). Validation only rejects names outside the list; a combination that does not fit the metric type surfaces at execution.

measures — tables with several value columns

A table like "requests, p50, p95 per endpoint" is built with measures. One query, one scan, values taken from the same rows, so the axes cannot drift apart.

{
  "id": "by-route",
  "title": "Requests by route",
  "layout": { "x": 0, "y": 0, "w": 12, "h": 8 },
  "visualization": { "type": "TABLE" },
  "queries": [
    {
      "refId": "A",
      "signal": "traces",
      "filters": [{ "field": "service.name", "operator": "IN", "value": "${service}" }],
      "groupBy": ["span.http.route"],
      "measures": [
        { "function": "COUNT",                     "alias": "requests" },
        { "function": "P50", "field": "duration_ms", "alias": "p50" },
        { "function": "P95", "field": "duration_ms", "alias": "p95" }
      ],
      "output": { "type": "TABLE" }
    }
  ]
}
RuleDetail
Result shapeTABLE only
With aggregationNot allowed — a single value column uses aggregation instead.
With recordsNot allowed — raw rows have no value columns.
CountAt most 8
Column namealias; without one the function name is used, and a collision is DUPLICATE.

records — raw rows

Returns log or trace rows as they are, without aggregating. Seeing "5 errors" is only useful if you can then read those five lines.

{
  "id": "recent",
  "title": "Recent logs",
  "layout": { "x": 0, "y": 0, "w": 12, "h": 10 },
  "visualization": { "type": "LOGS" },
  "queries": [
    {
      "refId": "A",
      "signal": "logs",
      "records": true,
      "filters": [{ "field": "level", "operator": "EQ", "value": "error" }],
      "output": { "type": "TABLE" },
      "alias": "logs"
    }
  ]
}
RuleDetail
Signallogs and traces only — metrics have no raw row.
Result shapeTABLE only
aggregation, groupBy, ratioCannot be combined with it.
Rows200 on screen; the panel pages on to the rest when there is more.
Default orderLogs by timestamp descending, traces by duration_ms descending
Changing the orderPick it with orderBy.

orderBy — ordering the raw table

orderBy looks like { "field": "timestamp", "desc": true }. Only columns carried by that table can be chosen — ordering by a column nobody can see leaves the screen unable to explain the result.

SignalOrderable columns
logstimestamp · service · level · body · trace_id
tracestimestamp · service · name · duration_ms · status_code · trace_id

This is what makes a panel like "recent error traces" possible; with the default order alone you only ever get the slowest ones.

orderBy on a query that is not records is rejected with INVALID_VALUE — the order of an aggregated result is already fixed to value descending. Pointing at a column the table does not carry is UNKNOWN_FIELD.

ratio — division

Divides two queries of the same panel. There is exactly one shape, "A ÷ B", which is what error rate and success rate need.

{
  "id": "error-rate",
  "title": "Error rate",
  "layout": { "x": 0, "y": 0, "w": 3, "h": 4 },
  "visualization": { "type": "NUMBER" },
  "queries": [
    { "refId": "A", "output": { "type": "SCALAR" },
      "ratio": { "numerator": "B", "denominator": "C" }, "alias": "error rate" },

    { "refId": "B", "signal": "traces", "aggregation": { "function": "COUNT" },
      "filters": [{ "field": "has_error", "operator": "EQ", "value": true }],
      "output": { "type": "SCALAR" } },

    { "refId": "C", "signal": "traces", "aggregation": { "function": "COUNT" },
      "output": { "type": "SCALAR" } }
  ]
}
RuleDetail
Result shapeTIME_SERIES or SCALAR; TABLE is not supported.
Cannot carrysignal, filters, groupBy, aggregation, source — it never reads storage itself.
Can point atA storage query in the same panel. Not itself, and not another ratio query.
Shape matchNumerator and denominator must have the same output.type as the ratio query.

limit

Caps how many series a time series panel draws. The largest series are chosen first and only then spread over time, so hitting the cap never truncates the time range. 0 means the default of 20, and the maximum is 100. Asking for more is rejected with OUT_OF_RANGE rather than silently folded.

Whether a result was capped is reported in the execute response as meta.truncated and meta.series_limit.

Normalization

Once a document passes validation the server normalizes it before storing, so what is stored may differ from what you sent.

NormalizationDetail
Defaults filledEmpty entries of settings
Empty arraysnull becomes [] for variables, sections, panels, filters, groupBy
UppercasedOperator and aggregation function names

Validation errors

Errors come back collected in one response. path is a JSON Pointer to the exact spot, and code is a stable identifier that survives wording changes.

{
  "valid": false,
  "schema_version": 1,
  "summary": { "panel_count": 1, "variable_count": 0, "section_count": 0 },
  "errors": [
    {
      "path": "/panels/0/queries/0/groupBy",
      "code": "REQUIRED",
      "message": "a TABLE result needs at least one group by"
    },
    {
      "path": "/panels/0/layout",
      "code": "OUT_OF_RANGE",
      "message": "panel exceeds the 12 column grid (x=8, w=6)"
    }
  ]
}
CodeMeaning
UNSUPPORTED_SCHEMA_VERSIONUnreadable schemaVersion (or format_version on an import document)
REQUIREDA required entry is missing
DUPLICATEA name, ID, or column name repeats
UNKNOWN_REFERENCEPoints at a panel that does not exist
OUT_OF_RANGEOutside the grid, count, or cap
INVALID_VALUEA value or combination that is not allowed
INCOMPATIBLE_OUTPUTVisualization and result shape do not match
UNKNOWN_FIELDNot in the dictionary, or not usable as an aggregation argument

Codes raised during execution are not validation errors. The definition is stored, one query could not produce an answer, and the other panels still render.

Execution codeMeaning
QUERY_FAILEDThat query failed to execute
METRIC_NOT_INSTRUMENTEDThe metric it points at exists nowhere in the retention window — not a fault, but a sign that instrumentation would fill it. message carries the metric name.

Seeing real definitions

The built-in templates are the best examples. Create a dashboard from one and press export to get the finished definition document.

Table of Contents