Skip to content

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.