Cookbook
Complete, working recipes. Each is a full *.frame.json you can drop under
@frames/ in your workspace and open with noemata up. They build on the
OpenTelemetry semantic layer (@opentelemetry_core/traces), so they assume the
OpenTelemetry integration is installed — see Views.
After copying a recipe, always run noemata validate and fix any reported
errors before rendering.
Recipe 1 — A single time-series panel
The smallest useful dashboard: one metric over time. The plot has no from, so
it queries the view automatically, bucketed by the base view’s timestamp.
{ "title": "Latency overview", "view": { "tables": [{ "from": { "frame": "@opentelemetry_core/traces" } }] }, "page": { "@block/panel": { "title": "Latency (p95)", "@block/plot": { "marks": [{ "line": { "y": "DurationP95" } }] } } }}Recipe 2 — A RED dashboard (rate, errors, duration)
The canonical service-health layout: a row of KPI stats over a row of trend
charts, in a grid. Every metric (Throughput, EntryErrorRate, DurationP95)
is defined once in the base view and referenced by name.
{ "title": "Service health (RED)", "view": { "tables": [{ "from": { "frame": "@opentelemetry_core/traces" } }], "where": "IsEntrySpan" }, "page": { "@block/grid": { "cols": 3, "default_rows": 1, "items": [ { "x": 0, "y": 0, "cols": 1, "rows": 1, "@block/stat": { "title": "Request rate", "format": { "rate": "seconds" }, "value": { "@expr/query": { "from": "otel_traces", "select": [{ "Rps": "count()" }] } } } }, { "x": 1, "y": 0, "cols": 1, "rows": 1, "@block/stat": { "title": "Error rate", "format": "percent", "value": { "@expr/query": { "from": "otel_traces", "select": [{ "E": "EntryErrorRate" }] } } } }, { "x": 2, "y": 0, "cols": 1, "rows": 1, "@block/stat": { "title": "Latency p95", "format": { "duration": "milliseconds" }, "value": { "@expr/query": { "from": "otel_traces", "select": [{ "D": "DurationP95" }] } } } },
{ "x": 0, "y": 1, "cols": 1, "rows": 2, "@block/panel": { "title": "Throughput", "@block/plot": { "marks": [{ "areaY": { "y": "Throughput" } }] } } }, { "x": 1, "y": 1, "cols": 1, "rows": 2, "@block/panel": { "title": "Error rate", "@block/plot": { "marks": [{ "line": { "y": "EntryErrorRate" } }] } } }, { "x": 2, "y": 1, "cols": 1, "rows": 2, "@block/panel": { "title": "Latency", "@block/plot": { "marks": [{ "line": { "y": "DurationP50" } }, { "line": { "y": "DurationP95" } }] } } } ] } }}Recipe 3 — A service inventory table
A list of entities with per-row metrics, sorted by load. @expr/query
aggregates by ServiceName; the table renders the columns.
{ "title": "Services", "view": { "tables": [{ "from": { "frame": "@opentelemetry_core/traces" } }] }, "page": { "@block/panel": { "title": "Services by request volume", "@block/table": { "from": { "@expr/query": { "from": "otel_traces", "select": [ "ServiceName", { "Requests": "count()" }, { "ErrorRate": "EntryErrorRate" }, { "P95": "DurationP95" } ], "where": "IsEntrySpan AND ServiceName != ''", "group_by": ["ServiceName"], "order_by": { "Requests": "desc" }, "limit": 50 } }, "columns": [ { "title": "Service", "column": "ServiceName" }, { "title": "Requests", "column": "Requests" }, { "title": "Error rate", "column": "ErrorRate" }, { "title": "Latency p95", "column": "P95" } ] } } }}Recipe 4 — A parameterized entity dashboard
To make one definition serve every service, declare a param
and let it auto-scope the view. Place the file at a templated path —
@frames/services/{ServiceName}/index.frame.json — and Noemata routes
?ServiceName=checkout to it, scoping every query to that service.
{ "title": "{{ServiceName}}", "params": [{ "type": "string", "column": "ServiceName", "required": true }], "view": { "tables": [{ "from": { "frame": "@opentelemetry_core/traces" } }], "where": "IsEntrySpan" }, "page": { "@block/grid": { "cols": 2, "default_rows": 2, "items": [ { "x": 0, "y": 0, "cols": 1, "rows": 2, "@block/panel": { "title": "Latency", "@block/plot": { "marks": [{ "line": { "y": "DurationP95" } }] } } }, { "x": 1, "y": 0, "cols": 1, "rows": 2, "@block/panel": { "title": "Error rate", "@block/plot": { "marks": [{ "line": { "y": "EntryErrorRate" } }] } } } ] } }}The installed @frames/@opentelemetry/services/{ServiceName} frame is a
fuller version of this — tabs, baselines (transform.shift), and shared
context. Read it next for the advanced patterns.