From 44aa5d73a29f004a4e9e29936013758b472362e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Pa=C3=9F?= <22845248+mpass99@users.noreply.github.com> Date: Wed, 26 Oct 2022 16:51:56 +0100 Subject: [PATCH] Grafana as Code Transfer our dashboard into a code representation via grafanalib. --- deploy/grafana-dashboard/.gitignore | 2 + deploy/grafana-dashboard/Readme.md | 16 + deploy/grafana-dashboard/availability_row.py | 51 + deploy/grafana-dashboard/color_mapping.py | 21 + deploy/grafana-dashboard/general_row.py | 112 ++ deploy/grafana-dashboard/main.json | 1746 ----------------- deploy/grafana-dashboard/main.py | 5 + .../grafana-dashboard/poseidon.dashboard.py | 25 + .../queries/current-environment-count.flux | 19 + .../queries/currently-used-runners.flux | 8 + .../queries/environment-ids.flux | 6 + .../queries/execution-duration-hist.flux | 27 + .../queries/execution-duration.flux | 28 + .../queries/executions-per-minute-time.flux | 27 + .../queries/executions-per-minute.flux | 28 + .../queries/executions-per-runner-hist.flux | 37 + .../queries/executions-per-runner.flux | 37 + .../queries/idle-runner.flux | 25 + .../queries/number-of-executions.flux | 26 + .../queries/prewarming-pool-size.flux | 25 + .../queries/request-body-size.flux | 25 + .../queries/request-latency.flux | 7 + .../queries/requests-per-minute.flux | 17 + .../queries/runner-per-minute.flux | 29 + .../queries/runner-startup-duration.flux | 25 + .../queries/service-time.flux | 7 + deploy/grafana-dashboard/queries/stages.flux | 6 + .../queries/used-runner.flux | 8 + .../grafana-dashboard/runner_insights_row.py | 66 + deploy/grafana-dashboard/util.py | 5 + deploy/grafana-dashboard/variables.py | 25 + 31 files changed, 745 insertions(+), 1746 deletions(-) create mode 100644 deploy/grafana-dashboard/.gitignore create mode 100644 deploy/grafana-dashboard/Readme.md create mode 100644 deploy/grafana-dashboard/availability_row.py create mode 100644 deploy/grafana-dashboard/color_mapping.py create mode 100644 deploy/grafana-dashboard/general_row.py delete mode 100644 deploy/grafana-dashboard/main.json create mode 100644 deploy/grafana-dashboard/main.py create mode 100644 deploy/grafana-dashboard/poseidon.dashboard.py create mode 100644 deploy/grafana-dashboard/queries/current-environment-count.flux create mode 100644 deploy/grafana-dashboard/queries/currently-used-runners.flux create mode 100644 deploy/grafana-dashboard/queries/environment-ids.flux create mode 100644 deploy/grafana-dashboard/queries/execution-duration-hist.flux create mode 100644 deploy/grafana-dashboard/queries/execution-duration.flux create mode 100644 deploy/grafana-dashboard/queries/executions-per-minute-time.flux create mode 100644 deploy/grafana-dashboard/queries/executions-per-minute.flux create mode 100644 deploy/grafana-dashboard/queries/executions-per-runner-hist.flux create mode 100644 deploy/grafana-dashboard/queries/executions-per-runner.flux create mode 100644 deploy/grafana-dashboard/queries/idle-runner.flux create mode 100644 deploy/grafana-dashboard/queries/number-of-executions.flux create mode 100644 deploy/grafana-dashboard/queries/prewarming-pool-size.flux create mode 100644 deploy/grafana-dashboard/queries/request-body-size.flux create mode 100644 deploy/grafana-dashboard/queries/request-latency.flux create mode 100644 deploy/grafana-dashboard/queries/requests-per-minute.flux create mode 100644 deploy/grafana-dashboard/queries/runner-per-minute.flux create mode 100644 deploy/grafana-dashboard/queries/runner-startup-duration.flux create mode 100644 deploy/grafana-dashboard/queries/service-time.flux create mode 100644 deploy/grafana-dashboard/queries/stages.flux create mode 100644 deploy/grafana-dashboard/queries/used-runner.flux create mode 100644 deploy/grafana-dashboard/runner_insights_row.py create mode 100644 deploy/grafana-dashboard/util.py create mode 100644 deploy/grafana-dashboard/variables.py diff --git a/deploy/grafana-dashboard/.gitignore b/deploy/grafana-dashboard/.gitignore new file mode 100644 index 0000000..8a838aa --- /dev/null +++ b/deploy/grafana-dashboard/.gitignore @@ -0,0 +1,2 @@ +# Ignore the generated json encoded dashboard. +./main.json diff --git a/deploy/grafana-dashboard/Readme.md b/deploy/grafana-dashboard/Readme.md new file mode 100644 index 0000000..21d7972 --- /dev/null +++ b/deploy/grafana-dashboard/Readme.md @@ -0,0 +1,16 @@ +# Grafana Dashboard Deployment + +## Grafanalib + +We use [Grafanalib](https://github.com/weaveworks/grafanalib) for the definition of our dashboard. +You need to install the python package: `pip install grafanalib`. + +### Generation + +Generate the Grafana dashboard by running `main.py`. +The generated Json definition can be imported in the Grafana UI. + +### Deployment + +You can copy the generated json into the field under the dashboards setting -> "JSON Model". +The version number needs to match! diff --git a/deploy/grafana-dashboard/availability_row.py b/deploy/grafana-dashboard/availability_row.py new file mode 100644 index 0000000..338f01b --- /dev/null +++ b/deploy/grafana-dashboard/availability_row.py @@ -0,0 +1,51 @@ +from grafanalib.core import RowPanel, BarGauge, GridPos, TimeSeries, ORIENTATION_VERTICAL, \ + GAUGE_DISPLAY_MODE_BASIC +from grafanalib.influxdb import InfluxDBTarget + +from util import read_query + +prewarming_pool_size = BarGauge( + title="Prewarming Pool Size", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("prewarming-pool-size"))], + gridPos=GridPos(h=10, w=11, x=0, y=3), + allValues=True, + orientation=ORIENTATION_VERTICAL, + displayMode=GAUGE_DISPLAY_MODE_BASIC, + max=None, +) + +idle_runner = TimeSeries( + title="Idle Runner", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("idle-runner"))], + gridPos=GridPos(h=10, w=13, x=11, y=3), + lineInterpolation="stepAfter", +) + +runner_startup_duration = TimeSeries( + title="Runner startup duration", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("runner-startup-duration"))], + gridPos=GridPos(h=10, w=12, x=0, y=13), + unit="ns", +) + +used_runner = TimeSeries( + title="Used Runner", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("used-runner"))], + gridPos=GridPos(h=10, w=12, x=12, y=13), +) + +availability_row = RowPanel( + title="Availability", + collapsed=True, + gridPos=GridPos(h=1, w=24, x=0, y=2), + panels=[ + prewarming_pool_size, + idle_runner, + runner_startup_duration, + used_runner + ] +) \ No newline at end of file diff --git a/deploy/grafana-dashboard/color_mapping.py b/deploy/grafana-dashboard/color_mapping.py new file mode 100644 index 0000000..a9a8e8e --- /dev/null +++ b/deploy/grafana-dashboard/color_mapping.py @@ -0,0 +1,21 @@ +def color_mapping(name, color): + return { + "fieldConfig": { + "overrides": [{ + "matcher": { + "id": "byName", + "options": name + }, + "properties": [{ + "id": "color", + "value": { + "fixedColor": color, + "mode": "fixed" + } + }] + }] + } + } + + +grey_all_mapping = color_mapping("all", "#4c4b5a") diff --git a/deploy/grafana-dashboard/general_row.py b/deploy/grafana-dashboard/general_row.py new file mode 100644 index 0000000..04258ea --- /dev/null +++ b/deploy/grafana-dashboard/general_row.py @@ -0,0 +1,112 @@ +from grafanalib.core import RowPanel, GridPos, Stat, TimeSeries, Heatmap, BarGauge, GAUGE_DISPLAY_MODE_GRADIENT +from grafanalib.influxdb import InfluxDBTarget + +from color_mapping import grey_all_mapping +from util import read_query + +requests_per_minute = TimeSeries( + title="Requests per minute", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("requests-per-minute"))], + gridPos=GridPos(h=9, w=8, x=0, y=1), + scaleDistributionType="log", + extraJson=grey_all_mapping +) + +request_latency = Heatmap( + title="Request Latency", + dataSource='Poseidon', + dataFormat="timeseries", + targets=[InfluxDBTarget(query=read_query("request-latency"))], + gridPos=GridPos(h=9, w=8, x=8, y=1), + extraJson={ + "options": {}, + "yAxis": { + "format": "ns" + } + } +) + +service_time = TimeSeries( + title="Service time (99.9%)", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("service-time"))], + gridPos=GridPos(h=9, w=8, x=16, y=1), + scaleDistributionType="log", + scaleDistributionLog=10, + unit="ns" +) + +current_environment_count = Stat( + title="Current environment count", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("current-environment-count"))], + gridPos=GridPos(h=6, w=8, x=0, y=10), + alignment='center' +) + +currently_used_runners = Stat( + title="Currently used runners", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("currently-used-runners"))], + gridPos=GridPos(h=6, w=8, x=8, y=10), + alignment="center" +) + +number_of_executions = BarGauge( + title="Number of Executions", + dataSource="Poseidon", + targets=[InfluxDBTarget(query=read_query("number-of-executions"))], + gridPos=GridPos(h=6, w=8, x=16, y=10), + allValues=True, + displayMode=GAUGE_DISPLAY_MODE_GRADIENT, + max=None, +) + +execution_duration = BarGauge( + title="Execution duration", + dataSource="Poseidon", + targets=[InfluxDBTarget(query=read_query("execution-duration"))], + gridPos=GridPos(h=11, w=8, x=0, y=16), + allValues=True, + displayMode=GAUGE_DISPLAY_MODE_GRADIENT, + format="ns", + max=None, +) + +executions_per_runner = BarGauge( + title="Executions per runner", + dataSource="Poseidon", + targets=[InfluxDBTarget(query=read_query("executions-per-runner"))], + gridPos=GridPos(h=11, w=8, x=8, y=16), + allValues=True, + displayMode=GAUGE_DISPLAY_MODE_GRADIENT, + max=None, +) + +executions_per_minute = BarGauge( + title="Executions per minute", + dataSource="Poseidon", + targets=[InfluxDBTarget(query=read_query("executions-per-minute"))], + gridPos=GridPos(h=11, w=8, x=16, y=16), + allValues=True, + displayMode=GAUGE_DISPLAY_MODE_GRADIENT, + max=None, +) + +general_row = RowPanel( + title="General", + collapsed=True, + gridPos=GridPos(h=1, w=24, x=0, y=0), + panels=[ + requests_per_minute, + request_latency, + service_time, + current_environment_count, + currently_used_runners, + number_of_executions, + execution_duration, + executions_per_runner, + executions_per_minute + ] +) diff --git a/deploy/grafana-dashboard/main.json b/deploy/grafana-dashboard/main.json deleted file mode 100644 index a41c59f..0000000 --- a/deploy/grafana-dashboard/main.json +++ /dev/null @@ -1,1746 +0,0 @@ -{ - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "datasource", - "uid": "grafana" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 13, - "iteration": 1660256037912, - "links": [], - "liveNow": false, - "panels": [ - { - "collapsed": false, - "datasource": { - "type": "influxdb", - "uid": "w2iPT7fGz" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 25, - "panels": [], - "title": "General", - "type": "row" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 2, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "all" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#4c4b5a", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 9, - "w": 8, - "x": 0, - "y": 1 - }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "import \"date\"\n\ndata = from(bucket: \"poseidon/autogen\")\n |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m))\n |> filter(fn: (r) => r._field == \"duration\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> keep(columns: [\"_time\", \"_value\", \"status\"])\n\nall = data |> set(key: \"status\", value: \"all\")\n\nresult = union(tables: [data, all])\n |> aggregateWindow(every: 1m, fn: count, createEmpty: true)\n\nif int(v: v.windowPeriod) > int(v: 1m) \n then result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 20), fn: mean, createEmpty: true)\n else result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 5), fn: mean, createEmpty: false)\n", - "refId": "A" - } - ], - "title": "Requests per minute", - "type": "timeseries" - }, - { - "cards": {}, - "color": { - "cardColor": "#b4ff00", - "colorScale": "sqrt", - "colorScheme": "interpolateOranges", - "exponent": 0.5, - "mode": "spectrum" - }, - "dataFormat": "timeseries", - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "gridPos": { - "h": 9, - "w": 8, - "x": 8, - "y": 1 - }, - "heatmap": {}, - "hideZeroBuckets": false, - "highlightCards": true, - "id": 28, - "legend": { - "show": false - }, - "pluginVersion": "8.4.6", - "reverseYBuckets": false, - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> keep(columns: [\"_time\", \"_value\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n", - "refId": "A" - } - ], - "title": "Request Latency", - "tooltip": { - "show": true, - "showHistogram": false - }, - "type": "heatmap", - "xAxis": { - "show": true - }, - "yAxis": { - "decimals": 1, - "format": "ns", - "logBase": 1, - "show": true - }, - "yBucketBound": "auto" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 10, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "ns" - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 8, - "x": 16, - "y": 1 - }, - "id": 27, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> keep(columns: [\"_time\", \"_value\", \"_measurement\"])\n |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 10), fn: (tables=<-, column) => tables |> quantile(q: 0.999))\n", - "refId": "A" - } - ], - "title": "Service time (99.9%)", - "type": "timeseries" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "fixed" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 10 - }, - "id": 41, - "options": { - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": true - }, - "showThresholdLabels": false, - "showThresholdMarkers": false - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "import \"date\"\n\n// The need for the date truncation is caused by Poseidon sending all influx events at the same time when starting up. This way not the last but a random value is displayed.\n// Since in this startup process the highes value is the correct one, we choose the highest value of the last events.\n\ndata = from(bucket: \"poseidon/autogen\")\n |> range(start: -1y)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_environments\")\n |> group(columns: [\"stage\"], mode:\"by\")\n |> map(fn: (r) => ({ r with _time: date.truncate(t: r._time, unit: 1m) }))\n\ndeploy_times = data\n |> last()\n |> keep(columns: [\"stage\", \"_time\"])\n\njoin(tables: {key1: data, key2: deploy_times}, on: [\"stage\", \"_time\"], method: \"inner\")\n |> max()\n |> keep(columns: [\"stage\", \"_value\"])\n |> rename(columns: {_value: \"\"})\n", - "refId": "A" - } - ], - "title": "Current environment count", - "type": "gauge" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "fixed" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 10 - }, - "id": 42, - "options": { - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": true - }, - "showThresholdLabels": false, - "showThresholdMarkers": true - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_used_runners\")\n |> filter(fn: (r) => r[\"_field\"] == \"count\")\n |> group(columns: [\"stage\"], mode:\"by\")\n |> last()\n |> keep(columns: [\"_value\", \"stage\"])\n |> rename(columns: {_value: \"\"})\n", - "refId": "A" - } - ], - "title": "Currently used runners", - "type": "gauge" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "continuous-GrYlRd" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 10 - }, - "id": 37, - "options": { - "displayMode": "gradient", - "minVizHeight": 10, - "minVizWidth": 0, - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_aws_executions\" or r[\"_measurement\"] == \"poseidon_nomad_executions\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> filter(fn: (r) => not bool(v: r[\"isDeletion\"]))\n |> group(columns: [\"environment_id\", \"stage\"], mode:\"by\")\n |> count()\n |> keep(columns: [\"_value\", \"environment_id\"])\n |> rename(columns: {_value: \"env\"})\n", - "refId": "A" - } - ], - "title": "Number of Executions", - "type": "bargauge" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "super-light-green", - "value": null - }, - { - "color": "green", - "value": 1000000000 - }, - { - "color": "yellow", - "value": 2000000000 - }, - { - "color": "#EF843C", - "value": 3000000000 - }, - { - "color": "light-red", - "value": 4000000000 - }, - { - "color": "dark-red", - "value": 5000000000 - }, - { - "color": "dark-purple", - "value": 10000000000 - }, - { - "color": "#000000", - "value": 20000000000 - } - ] - }, - "unit": "ns" - }, - "overrides": [] - }, - "gridPos": { - "h": 11, - "w": 8, - "x": 0, - "y": 16 - }, - "id": 20, - "options": { - "displayMode": "gradient", - "minVizHeight": 10, - "minVizWidth": 0, - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": true - }, - "showUnfilled": true - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_/execute\" or r[\"_measurement\"] == \"poseidon_/files\" or r[\"_measurement\"] == \"poseidon_/websocket\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> filter(fn: (r) => exists r.environment_id)\n |> drop(columns: [\"_field\", \"environment_type\", \"status\", \"_measurement\"])\n |> group(columns: [\"environment_id\", \"runner_id\"])\n |> mean()\n |> group(columns: [\"environment_id\"])\n |> mean()\n |> map(fn: (r) => ({r with _value: r._value * 3.0})) // Each execution has three requests\n |> rename(columns: {_value: \"env\"})\n", - "refId": "A" - } - ], - "title": "Execution duration", - "type": "bargauge" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "continuous-RdYlGr" - }, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "super-light-green", - "value": null - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 11, - "w": 8, - "x": 8, - "y": 16 - }, - "id": 32, - "options": { - "displayMode": "gradient", - "minVizHeight": 10, - "minVizWidth": 0, - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": true - }, - "showUnfilled": true - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "data = from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n\nrunner_deletions = data\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_used_runners\")\n |> filter(fn: (r) => bool(v: r[\"isDeletion\"]))\n |> keep(columns: [\"id\"])\n |> rename(columns: {id: \"runner_id\"})\n\nexecutions = data\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_nomad_executions\" or r[\"_measurement\"] == \"poseidon_aws_executions\")\n |> filter(fn: (r) => not bool(v: r[\"isDeletion\"]))\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> keep(columns: [\"_value\", \"environment_id\", \"runner_id\"])\n |> count()\n\njoin(tables: {key1: executions, key2: runner_deletions}, on: [\"runner_id\"], method: \"inner\")\n |> keep(columns: [\"_value\", \"environment_id\"])\n |> mean()\n |> rename(columns: {_value: \"env\"})\n", - "refId": "A" - } - ], - "title": "Executions per runner", - "type": "bargauge" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "continuous-GrYlRd" - }, - "decimals": 2, - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "super-light-green", - "value": null - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 11, - "w": 8, - "x": 16, - "y": 16 - }, - "id": 26, - "options": { - "displayMode": "gradient", - "minVizHeight": 10, - "minVizWidth": 0, - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": true - }, - "showUnfilled": true - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "import \"date\"\n\nfrom(bucket: \"poseidon/autogen\")\n |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m))\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_aws_executions\" or r[\"_measurement\"] == \"poseidon_nomad_executions\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> filter(fn: (r) => not bool(v: r[\"isDeletion\"]))\n |> group(columns: [\"environment_id\", \"stage\"], mode:\"by\")\n |> aggregateWindow(every: 1m, fn: count, createEmpty: true)\n |> keep(columns: [\"_value\", \"environment_id\"])\n |> mean()\n |> rename(columns: {_value: \"env\"})\n", - "refId": "A" - } - ], - "title": "Executions per minute", - "type": "bargauge" - }, - { - "collapsed": false, - "datasource": { - "type": "influxdb", - "uid": "w2iPT7fGz" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 27 - }, - "id": 23, - "panels": [], - "title": "Runner Insights", - "type": "row" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 48, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1 - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - } - ] - }, - "unit": "ns" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "32" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "10" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "14" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "29" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "28" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "blue", - "mode": "fixed" - } - } - ] - }, - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "10" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - } - ] - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 28 - }, - "id": 29, - "options": { - "bucketOffset": 0, - "bucketSize": 100000000, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_/execute\" or r[\"_measurement\"] == \"poseidon_/files\" or r[\"_measurement\"] == \"poseidon_/websocket\")\n |> filter(fn: (r) => exists r.environment_id)\n |> keep(columns: [\"_time\", \"_value\", \"environment_id\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> map(fn: (r) => ({r with _value: r._value * 3.0})) // Each execution has three requests\n", - "refId": "A" - } - ], - "title": "Execution duration", - "type": "histogram" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1 - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "32" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "red", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "10" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "green", - "mode": "fixed" - } - } - ] - }, - { - "__systemRef": "hideSeriesFrom", - "matcher": { - "id": "byNames", - "options": { - "mode": "exclude", - "names": [ - "14" - ], - "prefix": "All except:", - "readOnly": true - } - }, - "properties": [ - { - "id": "custom.hideFrom", - "value": { - "legend": false, - "tooltip": false, - "viz": true - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "14" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "yellow", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "29" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "orange", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 11, - "x": 0, - "y": 36 - }, - "id": 33, - "options": { - "bucketOffset": 0, - "bucketSize": 1, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "data = from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n\nrunner_deletions = data\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_used_runners\")\n |> filter(fn: (r) => bool(v: r[\"isDeletion\"]))\n |> keep(columns: [\"_time\", \"id\"])\n |> rename(columns: {id: \"runner_id\"})\n\nexecutions = data\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_nomad_executions\" or r[\"_measurement\"] == \"poseidon_aws_executions\")\n |> filter(fn: (r) => not bool(v: r[\"isDeletion\"]))\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> keep(columns: [\"_value\", \"environment_id\", \"runner_id\"])\n |> count()\n\njoin(tables: {key1: executions, key2: runner_deletions}, on: [\"runner_id\"], method: \"inner\")\n |> keep(columns: [\"_value\", \"_time\", \"environment_id\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n", - "refId": "A" - } - ], - "title": "Executions per runner", - "type": "histogram" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "smooth", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 13, - "x": 11, - "y": 36 - }, - "id": 21, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "import \"date\"\n\nfrom(bucket: \"poseidon/autogen\")\n |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m))\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_/websocket\")\n |> keep(columns: [\"_time\", \"_value\", \"environment_id\"])\n |> aggregateWindow(every: 1m, fn: count, createEmpty: true)\n |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 10), fn: mean, createEmpty: true)\n", - "refId": "A" - } - ], - "title": "Executions per minute", - "type": "timeseries" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "log": 2, - "type": "log" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 11, - "x": 0, - "y": 46 - }, - "id": 38, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "result = from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"request_size\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => contains(value: r[\"status\"], set: ${status_codes:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> keep(columns: [\"_time\", \"_value\", \"environment_id\"])\n\nif int(v: v.windowPeriod) > int(v: 1m) \n then result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 10), fn: mean, createEmpty: true)\n else result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 5), fn: mean, createEmpty: false)\n", - "refId": "A" - } - ], - "title": "Request Body Size", - "type": "timeseries" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 13, - "x": 11, - "y": 46 - }, - "id": 30, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "import \"date\"\n\nresult = from(bucket: \"poseidon/autogen\")\n |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m))\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_used_runners\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> filter(fn: (r) => not bool(v: r[\"isDeletion\"]))\n |> group(columns: [\"environment_id\", \"stage\"], mode:\"by\")\n |> aggregateWindow(every: 1m, fn: count, createEmpty: true)\n |> keep(columns: [\"_value\", \"_time\", \"environment_id\"])\n\nif int(v: v.windowPeriod) > int(v: 2m) \n then result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 30), fn: mean, createEmpty: true)\n else result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 15), fn: mean, createEmpty: true)\n", - "refId": "A" - } - ], - "title": "Runner per minute", - "type": "timeseries" - }, - { - "collapsed": false, - "datasource": { - "type": "influxdb", - "uid": "w2iPT7fGz" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 56 - }, - "id": 36, - "panels": [], - "title": "Availability", - "type": "row" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "continuous-GrYlRd" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 9, - "x": 0, - "y": 57 - }, - "id": 34, - "options": { - "displayMode": "basic", - "minVizHeight": 10, - "minVizWidth": 0, - "orientation": "vertical", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showUnfilled": true - }, - "pluginVersion": "8.5.5", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: -1y)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_poolsize\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> group(columns: [\"environment_id\", \"stage\"], mode:\"by\")\n |> last()\n |> keep(columns: [\"_value\", \"environment_id\"])\n |> rename(columns: {_value: \"env\"})\n", - "refId": "A" - } - ], - "title": "Prewarming Pool Size", - "type": "bargauge" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 15, - "x": 9, - "y": 57 - }, - "id": 39, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_nomad_idle_runners\" and r[\"_field\"] == \"count\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> keep(columns: [\"_value\", \"_time\", \"environment_id\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n", - "refId": "A" - } - ], - "title": "Idle Runner", - "type": "timeseries" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "ns" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 12, - "x": 0, - "y": 67 - }, - "id": 44, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_nomad_idle_runners\")\n |> filter(fn: (r) => r[\"_field\"] == \"startup_duration\")\n |> filter(fn: (r) => contains(value: r[\"environment_id\"], set: ${environment_ids:json}))\n |> filter(fn: (r) => (not exists r.stage) or contains(value: r[\"stage\"], set: ${stages:json}))\n |> keep(columns: [\"_value\", \"_time\", \"environment_id\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", - "refId": "A" - } - ], - "title": "Runner startup duration", - "type": "timeseries" - }, - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 12, - "x": 12, - "y": 67 - }, - "id": 43, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "8.4.6", - "targets": [ - { - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"poseidon_used_runners\")\n |> filter(fn: (r) => r[\"_field\"] == \"count\")\n |> group(columns: [\"stage\"], mode:\"by\")\n |> keep(columns: [\"_value\", \"_time\", \"stage\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)", - "refId": "A" - } - ], - "title": "Used Runner", - "type": "timeseries" - } - ], - "refresh": "10s", - "schemaVersion": 36, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": { - "selected": true, - "text": [ - "production" - ], - "value": [ - "production" - ] - }, - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "definition": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> keep(columns: [\"stage\"])\n |> distinct(column: \"stage\")\n |> keep(columns: [\"_value\"])\n", - "description": "The stage of the Poseidon instance.", - "hide": 0, - "includeAll": true, - "label": "Stage", - "multi": true, - "name": "stages", - "options": [], - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> keep(columns: [\"stage\"])\n |> distinct(column: \"stage\")\n |> keep(columns: [\"_value\"])\n", - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" - }, - { - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "definition": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> keep(columns: [\"environment_id\"])\n |> distinct(column: \"environment_id\")\n |> keep(columns: [\"_value\"])\n", - "description": "All environments currently tracked by Poseidon", - "hide": 0, - "includeAll": true, - "label": "Environment IDs", - "multi": true, - "name": "environment_ids", - "options": [], - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> keep(columns: [\"environment_id\"])\n |> distinct(column: \"environment_id\")\n |> keep(columns: [\"_value\"])\n", - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" - }, - { - "current": { - "selected": true, - "text": [ - "All" - ], - "value": [ - "$__all" - ] - }, - "datasource": { - "type": "influxdb", - "uid": "cMBTRmQnz" - }, - "definition": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> keep(columns: [\"status\"])\n |> distinct(column: \"status\")\n |> keep(columns: [\"_value\"])\n", - "description": "The http status code of the Poseidon response.", - "hide": 0, - "includeAll": true, - "label": "Status Code", - "multi": true, - "name": "status_codes", - "options": [], - "query": "from(bucket: \"poseidon/autogen\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_field\"] == \"duration\")\n |> keep(columns: [\"status\"])\n |> distinct(column: \"status\")\n |> keep(columns: [\"_value\"])\n", - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "type": "query" - } - ] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "Poseidon", - "uid": "hQRzR1Qnz", - "version": 46, - "weekStart": "" -} \ No newline at end of file diff --git a/deploy/grafana-dashboard/main.py b/deploy/grafana-dashboard/main.py new file mode 100644 index 0000000..47b9c26 --- /dev/null +++ b/deploy/grafana-dashboard/main.py @@ -0,0 +1,5 @@ +#!/usr/bin/python3 +from grafanalib._gen import generate_dashboard + +if __name__ == '__main__': + generate_dashboard(args=['-o', 'main.json', 'poseidon.dashboard.py']) diff --git a/deploy/grafana-dashboard/poseidon.dashboard.py b/deploy/grafana-dashboard/poseidon.dashboard.py new file mode 100644 index 0000000..bf368b7 --- /dev/null +++ b/deploy/grafana-dashboard/poseidon.dashboard.py @@ -0,0 +1,25 @@ +from grafanalib.core import Dashboard, Templating, Time + +from availability_row import availability_row +from general_row import general_row +from runner_insights_row import runner_insights_row +from variables import stage_variable, environment_variable + +dashboard = Dashboard( + title="Poseidon autogen", + timezone="browser", + panels=[ + general_row, + runner_insights_row, + availability_row + ], + templating=Templating(list=[ + stage_variable, + environment_variable + ]), + editable=True, + refresh="30s", + time=Time('now-6h', 'now'), + uid="P21Bh1SVk", + version=1 +).auto_panel_ids() diff --git a/deploy/grafana-dashboard/queries/current-environment-count.flux b/deploy/grafana-dashboard/queries/current-environment-count.flux new file mode 100644 index 0000000..94333c8 --- /dev/null +++ b/deploy/grafana-dashboard/queries/current-environment-count.flux @@ -0,0 +1,19 @@ +import "date" + +// The need for the date truncation is caused by Poseidon sending all influx events at the same time when starting up. This way not the last but a random value is displayed. +// Since in this startup process the highest value is the correct one, we choose the highest value of the last events. + +data = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> group(columns: ["stage"], mode:"by") + |> map(fn: (r) => ({ r with _time: date.truncate(t: r._time, unit: 1m) })) + +deploy_times = data + |> last() + |> keep(columns: ["stage", "_time"]) + +join(tables: {key1: data, key2: deploy_times}, on: ["stage", "_time"], method: "inner") + |> max() + |> keep(columns: ["stage", "_value"]) + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/currently-used-runners.flux b/deploy/grafana-dashboard/queries/currently-used-runners.flux new file mode 100644 index 0000000..34d1167 --- /dev/null +++ b/deploy/grafana-dashboard/queries/currently-used-runners.flux @@ -0,0 +1,8 @@ +from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_measurement"] == "poseidon_used_runners") + |> filter(fn: (r) => r["_field"] == "count") + |> group(columns: ["stage"], mode:"by") + |> last() + |> keep(columns: ["_value", "stage"]) + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/environment-ids.flux b/deploy/grafana-dashboard/queries/environment-ids.flux new file mode 100644 index 0000000..181cea3 --- /dev/null +++ b/deploy/grafana-dashboard/queries/environment-ids.flux @@ -0,0 +1,6 @@ +from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "duration") + |> keep(columns: ["environment_id"]) + |> distinct(column: "environment_id") + |> keep(columns: ["_value"]) diff --git a/deploy/grafana-dashboard/queries/execution-duration-hist.flux b/deploy/grafana-dashboard/queries/execution-duration-hist.flux new file mode 100644 index 0000000..f66c141 --- /dev/null +++ b/deploy/grafana-dashboard/queries/execution-duration-hist.flux @@ -0,0 +1,27 @@ +import "strings" + +result = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "duration") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> filter(fn: (r) => r["_measurement"] == "poseidon_/execute" or r["_measurement"] == "poseidon_/files" or r["_measurement"] == "poseidon_/websocket") + |> filter(fn: (r) => exists r.environment_id) + |> keep(columns: ["_time", "_value", "environment_id", "stage"]) + |> aggregateWindow(every: v.windowPeriod, fn: mean) + |> map(fn: (r) => ({r with _value: r._value * 3.0})) // Each execution has three requests + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/execution-duration.flux b/deploy/grafana-dashboard/queries/execution-duration.flux new file mode 100644 index 0000000..8bfbcc2 --- /dev/null +++ b/deploy/grafana-dashboard/queries/execution-duration.flux @@ -0,0 +1,28 @@ +import "strings" + +result = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "duration") + |> filter(fn: (r) => r["_measurement"] == "poseidon_/execute" or r["_measurement"] == "poseidon_/files" or r["_measurement"] == "poseidon_/websocket") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> filter(fn: (r) => exists r.environment_id) + |> keep(columns: ["_value", "runner_id", "environment_id", "stage"]) + |> group(columns: ["environment_id", "stage"]) + |> mean() + |> map(fn: (r) => ({r with _value: r._value * 3.0})) // Each execution has three requests + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/executions-per-minute-time.flux b/deploy/grafana-dashboard/queries/executions-per-minute-time.flux new file mode 100644 index 0000000..27f65c6 --- /dev/null +++ b/deploy/grafana-dashboard/queries/executions-per-minute-time.flux @@ -0,0 +1,27 @@ +import "strings" +import "date" + +result = from(bucket: "poseidon/autogen") + |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m)) + |> filter(fn: (r) => r["_measurement"] == "poseidon_aws_executions" or r["_measurement"] == "poseidon_nomad_executions") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["environment_id", "stage"], mode:"by") + |> aggregateWindow(every: 1m, fn: count, createEmpty: true) + |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 5), fn: mean, createEmpty: true) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/executions-per-minute.flux b/deploy/grafana-dashboard/queries/executions-per-minute.flux new file mode 100644 index 0000000..88567da --- /dev/null +++ b/deploy/grafana-dashboard/queries/executions-per-minute.flux @@ -0,0 +1,28 @@ +import "date" +import "strings" + +data = from(bucket: "poseidon/autogen") + |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m)) + |> filter(fn: (r) => r["_measurement"] == "poseidon_aws_executions" or r["_measurement"] == "poseidon_nomad_executions") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["environment_id", "stage"], mode:"by") + |> aggregateWindow(every: 1m, fn: count, createEmpty: true) + |> keep(columns: ["_value", "environment_id", "stage"]) + |> mean() + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: data, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/executions-per-runner-hist.flux b/deploy/grafana-dashboard/queries/executions-per-runner-hist.flux new file mode 100644 index 0000000..ac00672 --- /dev/null +++ b/deploy/grafana-dashboard/queries/executions-per-runner-hist.flux @@ -0,0 +1,37 @@ +import "strings" + +data = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + +runner_deletions = data + |> filter(fn: (r) => r["_measurement"] == "poseidon_used_runners") + |> filter(fn: (r) => r["event_type"] == "deletion") + |> keep(columns: ["_time", "id", "stage"]) + |> rename(columns: {id: "runner_id"}) + +executions = data + |> filter(fn: (r) => r["_measurement"] == "poseidon_nomad_executions" or r["_measurement"] == "poseidon_aws_executions") + |> filter(fn: (r) => r["event_type"] == "creation") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> keep(columns: ["_value", "environment_id", "runner_id"]) + |> count() + +result = join(tables: {key1: executions, key2: runner_deletions}, on: ["runner_id"], method: "inner") + |> keep(columns: ["_value", "_time", "environment_id", "stage"]) + |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/executions-per-runner.flux b/deploy/grafana-dashboard/queries/executions-per-runner.flux new file mode 100644 index 0000000..83b08dd --- /dev/null +++ b/deploy/grafana-dashboard/queries/executions-per-runner.flux @@ -0,0 +1,37 @@ +import "strings" + +data = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + +runner_deletions = data + |> filter(fn: (r) => r["_measurement"] == "poseidon_used_runners") + |> filter(fn: (r) => r["event_type"] == "deletion") + |> keep(columns: ["id", "stage"]) + |> rename(columns: {id: "runner_id"}) + +executions = data + |> filter(fn: (r) => r["_measurement"] == "poseidon_nomad_executions" or r["_measurement"] == "poseidon_aws_executions") + |> filter(fn: (r) => r["event_type"] == "creation") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> keep(columns: ["_value", "environment_id", "runner_id"]) + |> count() + +result = join(tables: {key1: executions, key2: runner_deletions}, on: ["runner_id"], method: "inner") + |> keep(columns: ["_value", "environment_id", "stage"]) + |> mean() + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/idle-runner.flux b/deploy/grafana-dashboard/queries/idle-runner.flux new file mode 100644 index 0000000..6afaf76 --- /dev/null +++ b/deploy/grafana-dashboard/queries/idle-runner.flux @@ -0,0 +1,25 @@ +import "strings" + +myWindowPeriod = if int(v: v.windowPeriod) >= int(v: 30s) then duration(v: int(v: v.windowPeriod) * 5) else v.windowPeriod +result = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_measurement"] == "poseidon_nomad_idle_runners" and r["_field"] == "count") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> keep(columns: ["_value", "_time", "environment_id", "stage"]) + |> aggregateWindow(every: myWindowPeriod, fn: min, createEmpty: false) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/number-of-executions.flux b/deploy/grafana-dashboard/queries/number-of-executions.flux new file mode 100644 index 0000000..810ca60 --- /dev/null +++ b/deploy/grafana-dashboard/queries/number-of-executions.flux @@ -0,0 +1,26 @@ +import "strings" + +result = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_measurement"] == "poseidon_aws_executions" or r["_measurement"] == "poseidon_nomad_executions") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["environment_id", "stage"], mode:"by") + |> count() + |> keep(columns: ["_value", "environment_id", "stage"]) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["isDeletion"] == "false") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/prewarming-pool-size.flux b/deploy/grafana-dashboard/queries/prewarming-pool-size.flux new file mode 100644 index 0000000..9742226 --- /dev/null +++ b/deploy/grafana-dashboard/queries/prewarming-pool-size.flux @@ -0,0 +1,25 @@ +import "strings" + +result = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_poolsize") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> group(columns: ["environment_id", "stage"], mode:"by") + |> last() + |> keep(columns: ["_value", "environment_id", "stage"]) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/request-body-size.flux b/deploy/grafana-dashboard/queries/request-body-size.flux new file mode 100644 index 0000000..b655763 --- /dev/null +++ b/deploy/grafana-dashboard/queries/request-body-size.flux @@ -0,0 +1,25 @@ +import "strings" + +myWindowPeriod = if int(v: v.windowPeriod) > int(v: 1m) then duration(v: int(v: v.windowPeriod) * 10) else duration(v: int(v: v.windowPeriod) * 5) +result = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "request_size") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> keep(columns: ["_time", "_value", "environment_id", "stage"]) + |> aggregateWindow(every: myWindowPeriod, fn: mean, createEmpty: false) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/request-latency.flux b/deploy/grafana-dashboard/queries/request-latency.flux new file mode 100644 index 0000000..d4018fd --- /dev/null +++ b/deploy/grafana-dashboard/queries/request-latency.flux @@ -0,0 +1,7 @@ +from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "duration") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> keep(columns: ["_time", "_value"]) + |> aggregateWindow(every: v.windowPeriod, fn: mean) diff --git a/deploy/grafana-dashboard/queries/requests-per-minute.flux b/deploy/grafana-dashboard/queries/requests-per-minute.flux new file mode 100644 index 0000000..8b4cb92 --- /dev/null +++ b/deploy/grafana-dashboard/queries/requests-per-minute.flux @@ -0,0 +1,17 @@ +import "date" + +data = from(bucket: "poseidon/autogen") + |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m)) + |> filter(fn: (r) => r._field == "duration") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> keep(columns: ["_time", "_value", "status"]) + +all = data |> set(key: "status", value: "all") + +result = union(tables: [data, all]) + |> aggregateWindow(every: 1m, fn: count, createEmpty: true) + +if int(v: v.windowPeriod) > int(v: 1m) + then result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 2), fn: mean, createEmpty: true) + else result |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 5), fn: mean, createEmpty: false) diff --git a/deploy/grafana-dashboard/queries/runner-per-minute.flux b/deploy/grafana-dashboard/queries/runner-per-minute.flux new file mode 100644 index 0000000..f1dc6d9 --- /dev/null +++ b/deploy/grafana-dashboard/queries/runner-per-minute.flux @@ -0,0 +1,29 @@ +import "strings" +import "date" + +myWindowPeriod = if int(v: v.windowPeriod) > int(v: 2m) then duration(v: int(v: v.windowPeriod) * 30) else duration(v: int(v: v.windowPeriod) * 15) +result = from(bucket: "poseidon/autogen") + |> range(start: date.truncate(t: v.timeRangeStart, unit: 1m), stop: date.truncate(t: v.timeRangeStop, unit: 1m)) + |> filter(fn: (r) => r["_measurement"] == "poseidon_used_runners") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["environment_id", "stage"], mode:"by") + |> aggregateWindow(every: 1m, fn: count, createEmpty: true) + |> keep(columns: ["_value", "_time", "environment_id", "stage"]) + |> aggregateWindow(every: myWindowPeriod, fn: mean, createEmpty: true) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/runner-startup-duration.flux b/deploy/grafana-dashboard/queries/runner-startup-duration.flux new file mode 100644 index 0000000..cd3fa21 --- /dev/null +++ b/deploy/grafana-dashboard/queries/runner-startup-duration.flux @@ -0,0 +1,25 @@ +import "strings" + +result = from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_measurement"] == "poseidon_nomad_idle_runners") + |> filter(fn: (r) => r["_field"] == "startup_duration") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> keep(columns: ["_value", "_time", "environment_id", "stage"]) + |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) + +envMapping = from(bucket: "poseidon/autogen") + |> range(start: -1y) + |> filter(fn: (r) => r["_measurement"] == "poseidon_environments") + |> filter(fn: (r) => r["event_type"] == "creation") + |> group(columns: ["id", "stage"], mode:"by") + |> last() + |> keep(columns: ["id", "image", "stage"]) + |> rename(columns: {id: "environment_id"}) + |> map(fn: (r) => ({ r with image: strings.trimPrefix(v: r.image, prefix: "openhpi/co_execenv_") + "(" + strings.substring(v: r.stage, start: 0, end: 1) + r.environment_id + ")" })) + +join(tables: {key1: result, key2: envMapping}, on: ["environment_id", "stage"], method: "inner") + |> keep(columns: ["_value", "image", "_time"]) + |> group(columns: ["image"], mode: "by") + |> rename(columns: {_value: ""}) diff --git a/deploy/grafana-dashboard/queries/service-time.flux b/deploy/grafana-dashboard/queries/service-time.flux new file mode 100644 index 0000000..5450453 --- /dev/null +++ b/deploy/grafana-dashboard/queries/service-time.flux @@ -0,0 +1,7 @@ +from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "duration") + |> filter(fn: (r) => contains(value: r["environment_id"], set: ${environment_ids:json})) + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> keep(columns: ["_time", "_value", "_measurement"]) + |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 10), fn: (tables=<-, column) => tables |> quantile(q: 0.999)) diff --git a/deploy/grafana-dashboard/queries/stages.flux b/deploy/grafana-dashboard/queries/stages.flux new file mode 100644 index 0000000..e233864 --- /dev/null +++ b/deploy/grafana-dashboard/queries/stages.flux @@ -0,0 +1,6 @@ +from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_field"] == "duration") + |> keep(columns: ["stage"]) + |> distinct(column: "stage") + |> keep(columns: ["_value"]) diff --git a/deploy/grafana-dashboard/queries/used-runner.flux b/deploy/grafana-dashboard/queries/used-runner.flux new file mode 100644 index 0000000..61ea989 --- /dev/null +++ b/deploy/grafana-dashboard/queries/used-runner.flux @@ -0,0 +1,8 @@ +from(bucket: "poseidon/autogen") + |> range(start: v.timeRangeStart, stop: v.timeRangeStop) + |> filter(fn: (r) => r["_measurement"] == "poseidon_used_runners") + |> filter(fn: (r) => r["_field"] == "count") + |> filter(fn: (r) => (not exists r.stage) or contains(value: r["stage"], set: ${stages:json})) + |> group(columns: ["stage"], mode:"by") + |> keep(columns: ["_value", "_time", "stage"]) + |> aggregateWindow(every: duration(v: int(v: v.windowPeriod) * 5), fn: mean, createEmpty: false) diff --git a/deploy/grafana-dashboard/runner_insights_row.py b/deploy/grafana-dashboard/runner_insights_row.py new file mode 100644 index 0000000..970dd97 --- /dev/null +++ b/deploy/grafana-dashboard/runner_insights_row.py @@ -0,0 +1,66 @@ +from grafanalib.core import RowPanel, GridPos, Histogram, TimeSeries +from grafanalib.influxdb import InfluxDBTarget + +from util import read_query + +execution_duration_extra_json = { + "fieldConfig": { + "defaults": { + "unit": "ns" + } + } +} +execution_duration = Histogram( + title="Execution duration", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("execution-duration-hist"))], + gridPos=GridPos(h=8, w=24, x=0, y=2), + bucketSize=100000000, + colorMode="palette-classic", + extraJson=execution_duration_extra_json +) + +executions_per_runner = Histogram( + title="Executions per runner", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("executions-per-runner-hist"))], + gridPos=GridPos(h=10, w=11, x=0, y=10), + bucketSize=1, + colorMode="palette-classic", +) + +executions_per_minute = TimeSeries( + title="Executions per minute", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("executions-per-minute-time"))], + gridPos=GridPos(h=10, w=13, x=11, y=10), +) + +request_body_size = TimeSeries( + title="Request Body Size", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("request-body-size"))], + gridPos=GridPos(h=10, w=11, x=0, y=20), + scaleDistributionType="log", + unit="bytes", +) + +runner_per_minute = TimeSeries( + title="Runner per minute", + dataSource='Poseidon', + targets=[InfluxDBTarget(query=read_query("runner-per-minute"))], + gridPos=GridPos(h=10, w=13, x=11, y=20), +) + +runner_insights_row = RowPanel( + title="Runner Insights", + collapsed=True, + gridPos=GridPos(h=1, w=24, x=0, y=1), + panels=[ + execution_duration, + executions_per_runner, + executions_per_minute, + request_body_size, + runner_per_minute + ] +) diff --git a/deploy/grafana-dashboard/util.py b/deploy/grafana-dashboard/util.py new file mode 100644 index 0000000..55d473a --- /dev/null +++ b/deploy/grafana-dashboard/util.py @@ -0,0 +1,5 @@ + + +def read_query(name): + with open("queries/" + name + ".flux", 'r') as file: + return file.read() diff --git a/deploy/grafana-dashboard/variables.py b/deploy/grafana-dashboard/variables.py new file mode 100644 index 0000000..890f6e4 --- /dev/null +++ b/deploy/grafana-dashboard/variables.py @@ -0,0 +1,25 @@ +from grafanalib.core import Template + +from util import read_query + +stage_variable = Template( + dataSource="Poseidon", + label="Stage", + name="stages", + query=read_query("stages"), + refresh=1, + includeAll=True, + multi=True, + default="production" +) + +environment_variable = Template( + dataSource="Poseidon", + label="Environment IDs", + name="environment_ids", + query=read_query("environment-ids"), + refresh=1, + includeAll=True, + multi=True, + default="$__all" +) \ No newline at end of file