├── .gitignore ├── Makefile ├── README.rst ├── jsonnet_utils ├── __init__.py ├── cli.py ├── grafana_dashboard.py ├── prometheus_rule.py └── utils.py ├── requirements.txt ├── scripts ├── .gitkeep └── test.sh ├── setup.py ├── tests ├── source │ ├── prometheus-redis_rev1.json │ └── server-single_rev3.json └── test_query.py ├── vendor ├── grafana-builder │ └── grafana.libsonnet ├── grafonnet │ ├── alert_condition.libsonnet │ ├── annotation.libsonnet │ ├── cloudwatch.libsonnet │ ├── dashboard.libsonnet │ ├── elasticsearch.libsonnet │ ├── grafana.libsonnet │ ├── graph_panel.libsonnet │ ├── graphite.libsonnet │ ├── influxdb.libsonnet │ ├── link.libsonnet │ ├── prometheus.libsonnet │ ├── row.libsonnet │ ├── singlestat.libsonnet │ ├── sql.libsonnet │ ├── table_panel.libsonnet │ ├── template.libsonnet │ ├── text.libsonnet │ └── timepicker.libsonnet └── promgrafonnet │ ├── gauge.libsonnet │ ├── numbersinglestat.libsonnet │ └── promgrafonnet.libsonnet └── view ├── dag.css ├── dag.html ├── dag.js ├── favicon.ico ├── force.css ├── force.html ├── force.js ├── sankey.css ├── sankey.html └── sankey.js /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | venv 3 | *.pyc 4 | jsonnet_utils.egg-info 5 | dist 6 | build 7 | data 8 | view/data* 9 | scripts/*.py -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CWD=$(shell pwd) 2 | 3 | .PHONY: test 4 | 5 | test: 6 | python tests/test_query.py 7 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | ============= 3 | jsonnet-utils 4 | ============= 5 | 6 | Utility scripts to work with JSONNET and monitoring resource mixins. 7 | 8 | * Grafana dashboards 9 | * Prometheus alert and recording rules 10 | 11 | Commands 12 | ======== 13 | 14 | At the moment just a few utilities to work with Grafana dashboard and Prometheus 15 | alarm definition mixins. 16 | 17 | jsonnet-utils-prometheus-convert 18 | -------------------------------- 19 | 20 | Convert YAML rules to JSONNET format. 21 | 22 | Usage: ``jsonnet-utils-prometheus-convert [OPTIONS]`` 23 | 24 | Options: 25 | 26 | --source-path TEXT Path to search for the source YAML rules. 27 | --build-path TEXT Path to save converted JSONNET dashboards, none to print to console. 28 | 29 | Example usage: 30 | 31 | .. code:: 32 | 33 | jsonnet-utils-prometheus-convert --source-path=../data/alarms --build-path=./build 34 | Searching path `../data/alarms` for YAML rule definitions to convert ... 35 | Converted rules file `../data/alarms/alarms.yml` to `./build/alarms.jsonnet`. 36 | 37 | Example result JSONNET definition: 38 | 39 | .. code:: 40 | 41 | { 42 | prometheusAlerts+:: { 43 | groups+: [ 44 | { 45 | name: 'kubernetes-apps', 46 | rules: [ 47 | { 48 | alert: 'KubePodCrashLooping', 49 | annotations: { 50 | message: 'Pod {{ $labels.namespace }}/{{ $labels.pod }} ({{ $labels.container }}) is restarting {{ printf "%.2f" $value }} times / 5 minutes.', 51 | }, 52 | expr: 'rate(kube_pod_container_status_restarts_total{kubernetes_name="kube-state-metrics"}[15m]) * 60 * 5 > 0\n', 53 | 'for': '1h', 54 | labels: { 55 | severity: 'critical', 56 | }, 57 | }, 58 | { 59 | alert: 'KubePodNotReady', 60 | annotations: { 61 | message: 'Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-ready state for longer than an hour.', 62 | }, 63 | expr: 'sum by (namespace, pod) (kube_pod_status_phase{kubernetes_name="kube-state-metrics", phase=~"Pending|Unknown"}) > 0\n', 64 | 'for': '1h', 65 | labels: { 66 | severity: 'critical', 67 | }, 68 | }, 69 | ], 70 | }, 71 | ] 72 | } 73 | } 74 | 75 | 76 | jsonnet-utils-grafana-convert 77 | ----------------------------- 78 | 79 | Convert JSON dashboards to JSONNET format. 80 | 81 | Usage: ``jsonnet-utils-grafana-convert [OPTIONS]`` 82 | 83 | Options: 84 | 85 | --source-path TEXT Path to search for the source JSON dashboards. 86 | --build-path TEXT Path to save converted JSONNET dashboards, none to print to console. 87 | --format TEXT Format of the dashboard: `grafonnet` or `grafana-builder`. 88 | --layout TEXT Format of the dashboard: `normal` (scheme 14) , `grid` (scheme 16). 89 | 90 | Example usage: 91 | 92 | .. code:: 93 | 94 | jsonnet-utils-grafana-convert --source-path=./tests/data --build-path ./build 95 | Searching path `./tests/data` for JSON dashboards to convert ... 96 | Converted dashboard `./tests/data/server-single_rev3.json` to `./build/server-single_rev3.jsonnet` 97 | Converted dashboard `./tests/data/prometheus-redis_rev1.json` to `./build/prometheus-redis_rev1.jsonnet` 98 | 99 | Example result JSONNET definition: 100 | 101 | .. code:: 102 | 103 | local grafana = import 'grafonnet/grafana.libsonnet'; 104 | local dashboard = grafana.dashboard; 105 | local row = grafana.row; 106 | local prometheus = grafana.prometheus; 107 | local template = grafana.template; 108 | local graphPanel = grafana.graphPanel; 109 | { 110 | grafanaDashboards+:: { 111 | 'prometheus-redis_rev1.json': 112 | 113 | dashboard.new( 114 | 'Prometheus Redis', tags=[] 115 | ) 116 | 117 | .addTemplate('addr', 'label_values(redis_connected_clients, addr)', 'instance') 118 | .addRow( 119 | row.new() 120 | 121 | .addPanel( 122 | singlestat.new( 123 | 'Uptime', 124 | datasource='$datasource', 125 | span=1, 126 | format='s', 127 | valueName='current', 128 | ) 129 | ) 130 | 131 | .addTarget( 132 | prometheus.target( 133 | ||| 134 | redis_uptime_in_seconds{addr="$addr"} 135 | ||| % $._config, 136 | legendFormat='', 137 | ) 138 | ) 139 | 140 | .addPanel( 141 | singlestat.new( 142 | 'Clients', 143 | datasource='$datasource', 144 | span=1, 145 | format='none', 146 | valueName='current', 147 | ) 148 | ) 149 | 150 | .addTarget( 151 | prometheus.target( 152 | ||| 153 | redis_connected_clients{addr="$addr"} 154 | ||| % $._config, 155 | legendFormat='', 156 | ) 157 | ) 158 | ) 159 | } 160 | } 161 | 162 | 163 | jsonnet-utils-grafana-info 164 | -------------------------- 165 | 166 | Get info from Grafana JSON dashboards. 167 | 168 | Usage: ``jsonnet-utils-grafana-info [OPTIONS]`` 169 | 170 | Options: 171 | 172 | --path TEXT Path to search for the source JSON dashboards. 173 | 174 | Example usage: 175 | 176 | .. code:: 177 | 178 | jsonnet-utils-grafana-info --path=./tests/data 179 | Searching path `./tests/data` for JSON dashboards for detailed info ... 180 | 181 | server-single_rev3.json: 182 | title: Linux host 183 | schema-version: 14 184 | variables: 185 | count: 1 186 | items: 187 | - host (query) 188 | panels: 189 | count: 7 190 | items: 191 | - DISK partitions (graph) 192 | - Processes (graph) 193 | - swap (graph) 194 | - CPU usage (graph) 195 | - RAM (graph) 196 | - IP traffic (graph) 197 | - system: load (5m) (graph) 198 | 199 | prometheus-redis_rev1.json: 200 | title: Prometheus Redis 201 | schema-version: 12 202 | variables: 203 | count: 1 204 | items: 205 | - addr (query) 206 | panels: 207 | count: 11 208 | items: 209 | - Uptime (singlestat) 210 | - Clients (singlestat) 211 | - Memory Usage (singlestat) 212 | - Commands Executed / sec (graph) 213 | - Hits / Misses per Sec (graph) 214 | - Total Memory Usage (graph) 215 | - Network I/O (graph) 216 | - Total Items per DB (graph) 217 | - Expiring vs Not-Expiring Keys (graph) 218 | - Expired / Evicted (graph) 219 | - Command Calls / sec (graph) 220 | 221 | 222 | jsonnet-utils-grafana-test 223 | -------------------------- 224 | 225 | Test JSONNET formatted dashboards. 226 | 227 | Usage: ``jsonnet-utils-grafana-test [OPTIONS]`` 228 | 229 | 230 | Options: 231 | 232 | --path TEXT Path to search for the source JSON dashboards. 233 | --scheme TEXT Scheme version of the dashboard: `16` is the current. 234 | --layout TEXT Format of the dashboard: `normal` (scheme 14) , `grid` (scheme 16). 235 | 236 | Example usage: 237 | 238 | .. code:: 239 | 240 | jsonnet-utils-grafana-test --path=./tests/data 241 | 2018-11-28 00:50:02,298 [INFO ] Searching path `./tests/data` for JSON dashboards to test ... 242 | 2018-11-28 00:50:02,298 [INFO ] Testing dashboard `server-single_rev3.json` ... OK 243 | 2018-11-28 00:50:02,299 [INFO ] Testing dashboard `prometheus-redis_rev1.json` ... OK 244 | 245 | 246 | jsonnet-utils-grafana-metrics 247 | ----------------------------- 248 | 249 | Get Prometheus metric names from Grafana JSON dashboard targets. 250 | 251 | Usage: jsonnet-utils-grafana-metrics [OPTIONS] 252 | 253 | Options: 254 | 255 | --path TEXT Path to search for the source JSON dashboards. 256 | 257 | Example usage: 258 | 259 | .. code:: 260 | 261 | jsonnet-utils-grafana-metrics --path=./tests/source 262 | Searching path `./tests/source` for JSON dashboards for targets ... 263 | 264 | prometheus-redis_rev1.json: 265 | - redis_command_call_duration_seconds_count 266 | - redis_commands_processed_total 267 | - redis_config_maxmemory 268 | - redis_connected_clients 269 | - redis_db_keys 270 | - redis_db_keys_expiring 271 | - redis_evicted_keys_total 272 | - redis_expired_keys_total 273 | - redis_keyspace_hits_total 274 | - redis_keyspace_misses_total 275 | - redis_memory_used_bytes 276 | - redis_net_input_bytes_total 277 | - redis_net_output_bytes_total 278 | - redis_uptime_in_seconds 279 | 280 | 281 | Roadmap 282 | ======= 283 | 284 | * Convert row based layout to grid layout 285 | * Support for Prometheus, InfluxDB and ElasticSearch datasources 286 | * Testing of JSONNET sources and built resources 287 | -------------------------------------------------------------------------------- /jsonnet_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cznewt/jsonnet-utils/cf77802278b1d96e6e612987f18a57261329692f/jsonnet_utils/__init__.py -------------------------------------------------------------------------------- /jsonnet_utils/cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import os 6 | import click 7 | import logging 8 | from .grafana_dashboard import ( 9 | convert_dashboards, 10 | info_dashboards, 11 | test_dashboards, 12 | metrics_dashboards, 13 | metrics_all, 14 | ) 15 | from .prometheus_rule import convert_rules, metrics_rules, info_rules 16 | 17 | from .utils import is_debug_active 18 | 19 | logging.basicConfig( 20 | format="%(asctime)s [%(levelname)-5.5s] %(message)s", 21 | level=logging.INFO, 22 | handlers=[logging.StreamHandler()], 23 | ) 24 | 25 | 26 | def set_logger(): 27 | debug = is_debug_active() 28 | if debug: 29 | logging.getLogger().setLevel(logging.DEBUG) 30 | logging.info("Setting logging to DEBUG level...") 31 | else: 32 | logging.getLogger().setLevel(logging.INFO) 33 | logging.info("Setting logging to INFO level...") 34 | 35 | 36 | @click.command() 37 | @click.option( 38 | "--source-path", 39 | default="./source", 40 | help="Path to search for the source JSON dashboards.", 41 | ) 42 | @click.option( 43 | "--build-path", 44 | default="", 45 | help="Path to save converted JSONNET dashboards, none to print to console.", 46 | ) 47 | @click.option( 48 | "--format", 49 | default="grafonnet", 50 | help="Format of the dashboard: `grafonnet` or `grafana-builder`.", 51 | ) 52 | @click.option( 53 | "--layout", 54 | default="rows", 55 | help="Format of the dashboard: `normal` (scheme 14) , `grid` (scheme 16).", 56 | ) 57 | def dashboard_convert(source_path, build_path, format, layout): 58 | """Convert JSON dashboards to JSONNET format.""" 59 | logging.info( 60 | "Searching path `{}` for JSON dashboards to convert ...".format(source_path) 61 | ) 62 | set_logger() 63 | convert_dashboards(source_path, build_path, format, layout) 64 | 65 | 66 | @click.command() 67 | @click.option( 68 | "--path", default="./data", help="Path to search for the source JSON dashboards." 69 | ) 70 | @click.option( 71 | "--scheme", 72 | default="16", 73 | help="Scheme version of the dashboard: `16` is the current.", 74 | ) 75 | @click.option( 76 | "--layout", 77 | default="rows", 78 | help="Format of the dashboard: `normal` (scheme 14) , `grid` (scheme 16).", 79 | ) 80 | def dashboard_test(path, scheme, layout): 81 | """Test JSONNET formatted dashboards.""" 82 | logging.info("Searching path `{}` for JSON dashboards...".format(path)) 83 | set_logger() 84 | test_dashboards(path) 85 | 86 | 87 | @click.command() 88 | @click.option( 89 | "--path", default="./data", help="Path to search for the source JSON dashboards." 90 | ) 91 | def dashboard_info(path): 92 | """Get info from Grafana JSON dashboards.""" 93 | logging.info( 94 | "Searching path `{}` for JSON dashboards...".format(path) 95 | ) 96 | print(info_dashboards(path)) 97 | 98 | 99 | @click.command() 100 | @click.option( 101 | "--path", default="./data", help="Path to search for the JSON dashboards." 102 | ) 103 | def dashboard_metrics(path): 104 | """Get metric names from Grafana JSON dashboard targets.""" 105 | logging.info("Searching path `{}` for JSON dashboards...".format(path)) 106 | set_logger() 107 | metrics_dashboards(path) 108 | 109 | 110 | @click.command() 111 | @click.option( 112 | "--dashboard-path", 113 | default="./data/grafana", 114 | help="Path to search for the Grafana JSON dashboards.", 115 | ) 116 | @click.option( 117 | "--rules-path", 118 | default="./data/prometheus", 119 | help="Path to search for the Prometheus YAML rules.", 120 | ) 121 | @click.option("--output", default="console", help="Type of output [console/json]") 122 | def all_metrics(dashboard_path, rules_path, output): 123 | """Get metric names from Grafana JSON dashboard targets and Prometheus rules.""" 124 | logging.info( 125 | "Searching path `{}` for JSON dashboards for metrics ...".format(dashboard_path) 126 | ) 127 | logging.info( 128 | "Searching path `{}` for YAML rules for metrics ...".format(rules_path) 129 | ) 130 | set_logger() 131 | metrics_all(dashboard_path, rules_path, output) 132 | 133 | 134 | @click.command() 135 | @click.option( 136 | "--path", default="./data", help="Path to search for the YAML rule definions." 137 | ) 138 | def rule_info(path): 139 | """Get detailed info from Prometheus rule targets.""" 140 | logging.info( 141 | "Searching path `{}` for YAML rule definitions for detailed info ...".format( 142 | path 143 | ) 144 | ) 145 | set_logger() 146 | info_rules(path) 147 | 148 | 149 | @click.command() 150 | @click.option( 151 | "--path", default="./data", help="Path to search for the YAML rule definions." 152 | ) 153 | def rule_metrics(path): 154 | """Get metric names from Prometheus rule targets.""" 155 | logging.info( 156 | "Searching path `{}` for YAML rule definitions for metrics ...".format(path) 157 | ) 158 | set_logger() 159 | metrics_rules(path) 160 | 161 | 162 | @click.command() 163 | @click.option( 164 | "--source-path", 165 | default="./source", 166 | help="Path to search for the source YAML rule files.", 167 | ) 168 | @click.option( 169 | "--build-path", 170 | default="", 171 | help="Path to save converted JSONNET rules, none to print to console.", 172 | ) 173 | def rule_convert(source_path, build_path): 174 | """Convert Prometheus rule definitions to JSONNET format.""" 175 | logging.info( 176 | "Searching path `{}` for YAML rule definitions to convert ...".format( 177 | source_path 178 | ) 179 | ) 180 | set_logger() 181 | convert_rules(source_path, build_path) 182 | -------------------------------------------------------------------------------- /jsonnet_utils/grafana_dashboard.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re 3 | import os 4 | import glob 5 | import _jsonnet 6 | import logging 7 | import subprocess 8 | from .prometheus_rule import metrics_rules 9 | from .utils import search_prometheus_metrics, is_debug_active 10 | 11 | logging.basicConfig( 12 | format="%(asctime)s [%(levelname)-5.5s] %(message)s", 13 | level=logging.INFO, 14 | handlers=[logging.StreamHandler()], 15 | ) 16 | 17 | GRAFONNET_INCLUDES = """ 18 | local grafana = import 'grafonnet/grafana.libsonnet'; 19 | local dashboard = grafana.dashboard; 20 | local row = grafana.row; 21 | local prometheus = grafana.prometheus; 22 | local template = grafana.template; 23 | local graphPanel = grafana.graphPanel;""" 24 | 25 | GRAFONNET_DASHBOARD = """ 26 | dashboard.new(\n{}, tags={})""" 27 | 28 | GRAFONNET_ROW = """ 29 | row.new()""" 30 | 31 | GRAFONNET_GRAPH_PANEL = """ 32 | .addPanel( 33 | graphPanel.new( 34 | '{}', 35 | datasource='$datasource', 36 | span={}, 37 | format='{}', 38 | stack={}, 39 | min=0, 40 | ) 41 | )""" 42 | 43 | GRAFONNET_SINGLESTAT_PANEL = """ 44 | .addPanel( 45 | singlestat.new( 46 | '{}', 47 | datasource='$datasource', 48 | span={}, 49 | format='{}', 50 | valueName='current', 51 | ) 52 | )""" 53 | 54 | GRAFONNET_PROMETHEUS_TARGET = """ 55 | .addTarget( 56 | prometheus.target( 57 | ||| 58 | {} 59 | ||| % $._config, 60 | legendFormat='', 61 | ) 62 | )""" 63 | 64 | GRAFONNET_INFLUXDB_TARGET = """ 65 | .addTarget( 66 | influxdb.target( 67 | ||| 68 | {} 69 | ||| % $._config, 70 | alias='{}', 71 | ) 72 | )""" 73 | 74 | GRAPH_BUILDER_DASHBOARD = """ 75 | g.dashboard({}, tags={}) 76 | """ 77 | 78 | 79 | def print_dashboard_info(dashboard): 80 | output = [""] 81 | output.append( 82 | "## Dashboard {} (schema: {}, file: {})\n".format( 83 | dashboard.get("title", "N/A"), 84 | dashboard.get("schemaVersion", "N/A"), 85 | dashboard.get("_filename"), 86 | ) 87 | ) 88 | # output.append("variables:") 89 | # output.append( 90 | # " count: {}".format(len(dashboard.get("templating", {}).get("list", []))) 91 | # ) 92 | # output.append(" items:") 93 | # for variable in dashboard.get("templating", {}).get("list", []): 94 | # output.append(" - {} ({})".format(variable["name"], variable["type"])) 95 | # output.append(" panels:") 96 | # output.append(" count: {}".format(len(dashboard.get("_panels", [])))) 97 | # output.append(" items:") 98 | 99 | for panel in dashboard.get("_panels", []): 100 | panel_line = "* {} ({}): ".format( 101 | panel.get("title", "N/A"), panel.get("type", "N/A") 102 | ) 103 | panel_metrics = [] 104 | for target in panel["targets"]: 105 | if "expr" in target: 106 | if is_debug_active(): 107 | output.append( 108 | "* **{}**: {}".format( 109 | "**, **".join(search_prometheus_metrics(target["expr"])), 110 | target["expr"].replace("\n", " "), 111 | ) 112 | ) 113 | else: 114 | panel_metrics = panel_metrics + search_prometheus_metrics( 115 | target["expr"] 116 | ) 117 | output.append(panel_line + ", ".join(panel_metrics)) 118 | return "\n".join(output) 119 | 120 | 121 | def print_dashboard_metrics(dashboard): 122 | output = [""] 123 | metrics = [] 124 | output.append("{}:".format(dashboard.get("_filename"))) 125 | for panel in dashboard.get("_panels", []): 126 | for target in panel.get("targets", []): 127 | if "expr" in target: 128 | queries = search_prometheus_metrics(target["expr"]) 129 | metrics += queries 130 | final_metrics = sorted(list(set(metrics))) 131 | for metric in final_metrics: 132 | output.append("- {}".format(metric)) 133 | # for line in output: 134 | # print(line) 135 | return final_metrics 136 | 137 | 138 | def data_dashboard_metrics(dashboard): 139 | metrics = [] 140 | data = {"nodes": [], "links": []} 141 | data["nodes"].append( 142 | { 143 | "id": dashboard.get("_filename"), 144 | "type": "grafana-dashboard", 145 | "name": dashboard.get("_filename"), 146 | "sources": [], 147 | "targets": [], 148 | } 149 | ) 150 | data["links"].append( 151 | {"source": dashboard.get("_filename"), "target": "output", "value": 10} 152 | ) 153 | panels = dashboard.get("_panels", []) 154 | if len(panels) == 0: 155 | panels = dashboard.get("panels", []) 156 | for panel in panels: 157 | for target in panel.get("targets", []): 158 | if "expr" in target: 159 | queries = search_prometheus_metrics(target["expr"]) 160 | metrics += queries 161 | final_metrics = sorted(list(set(metrics))) 162 | for metric in final_metrics: 163 | data["links"].append( 164 | {"source": metric, "target": dashboard.get("_filename"), "value": 10} 165 | ) 166 | return data 167 | 168 | 169 | def convert_dashboard_jsonnet(dashboard, format, source_path, build_path): 170 | dashboard_lines = [] 171 | if format == "grafonnet": 172 | dashboard_lines.append(GRAFONNET_INCLUDES) 173 | dashboard_lines.append("{\ngrafanaDashboards+:: {") 174 | dashboard_lines.append("'{}':".format(dashboard["_filename"])) 175 | dashboard_lines.append( 176 | GRAFONNET_DASHBOARD.format('"' + dashboard.get("title", "N/A") + '"', []) 177 | ) 178 | for variable in dashboard.get("templating", {}).get("list", []): 179 | if variable["type"] == "query": 180 | if variable["multi"]: 181 | multi = "Multi" 182 | else: 183 | multi = "" 184 | dashboard_lines.append( 185 | "\n.add{}Template('{}', '{}', 'instance')".format( 186 | multi, variable["name"], variable["query"] 187 | ) 188 | ) 189 | for row in dashboard.get("rows", []): 190 | dashboard_lines.append(".addRow(") 191 | dashboard_lines.append("row.new()") 192 | for panel in row.get("panels", []): 193 | if panel["type"] == "singlestat": 194 | dashboard_lines.append( 195 | GRAFONNET_SINGLESTAT_PANEL.format( 196 | panel["title"], panel["span"], panel["format"] 197 | ) 198 | ) 199 | if panel["type"] == "graph": 200 | dashboard_lines.append( 201 | GRAFONNET_GRAPH_PANEL.format( 202 | panel["title"], 203 | panel["span"], 204 | panel["yaxes"][0]["format"], 205 | panel["stack"], 206 | ) 207 | ) 208 | for target in panel.get("targets", []): 209 | if "expr" in target: 210 | dashboard_lines.append( 211 | GRAFONNET_PROMETHEUS_TARGET.format(target["expr"]) 212 | ) 213 | dashboard_lines.append(")") 214 | 215 | dashboard_lines.append("}\n}") 216 | else: 217 | dashboard_body = GRAPH_BUILDER_DASHBOARD.format( 218 | '"' + dashboard.get("title", "N/A") + '"', [] 219 | ) 220 | for variable in dashboard.get("templating", {}).get("list", []): 221 | if variable["type"] == "query": 222 | if variable["multi"]: 223 | multi = "Multi" 224 | else: 225 | multi = "" 226 | dashboard_body += "\n.add{}Template('{}', '{}', 'instance')".format( 227 | multi, variable["name"], variable["query"] 228 | ) 229 | 230 | dashboard_str = "\n".join(dashboard_lines) 231 | 232 | if build_path == "": 233 | print("JSONNET:\n{}".format(dashboard_str)) 234 | print("JSON:\n{}".format(_jsonnet.evaluate_snippet("snippet", dashboard_str))) 235 | else: 236 | build_file = ( 237 | build_path + "/" + dashboard["_filename"].replace(".json", ".jsonnet") 238 | ) 239 | with open(build_file, "w") as the_file: 240 | the_file.write(dashboard_str) 241 | output = ( 242 | subprocess.Popen( 243 | "jsonnet fmt -n 2 --max-blank-lines 2 --string-style s --comment-style s -i " 244 | + build_file, 245 | shell=True, 246 | stdout=subprocess.PIPE, 247 | stderr=subprocess.STDOUT, 248 | ) 249 | .stdout.read() 250 | .decode("utf-8") 251 | ) 252 | if "ERROR" in output: 253 | logging.info( 254 | "Error `{}` converting dashboard `{}/{}` to `{}`".format( 255 | output, source_path, dashboard["_filename"], build_file 256 | ) 257 | ) 258 | else: 259 | logging.info( 260 | "Converted dashboard `{}/{}` to `{}` ({} format)".format( 261 | source_path, dashboard["_filename"], build_file, format 262 | ) 263 | ) 264 | 265 | return dashboard_str 266 | 267 | 268 | def parse_dashboard(board_file): 269 | with open(board_file) as f: 270 | dashboard = json.load(f) 271 | panels = [] 272 | if dashboard == None: 273 | dashboard["_filename"] = os.path.basename(board_file) 274 | dashboard["_panels"] = panels 275 | return dashboard 276 | for panel in dashboard.get("panels", []): 277 | if "targets" in panel: 278 | panels.append(panel) 279 | if dashboard.get("rows", []) == None: 280 | logging.error("Dashboard {} has Null row".format(board_file)) 281 | dashboard["rows"] = [] 282 | for row in dashboard.get("rows", []): 283 | for panel in row.get("panels", []): 284 | panels.append(panel) 285 | for subpanel in panel.get("panels", []): 286 | panels.append(subpanel) 287 | dashboard["_filename"] = os.path.basename(board_file) 288 | dashboard["_panels"] = panels 289 | return dashboard 290 | 291 | 292 | def info_dashboards(path): 293 | board_output = [] 294 | board_files = glob.glob("{}/*.json".format(path)) 295 | for board_file in board_files: 296 | dashboard = parse_dashboard(board_file) 297 | board_output.append(print_dashboard_info(dashboard)) 298 | if len(board_files) == 0: 299 | logging.error("No dashboards found at path {}!".format(path)) 300 | return "\n".join(board_output) 301 | 302 | 303 | def metrics_dashboards(path, output="console"): 304 | board_files = glob.glob("{}/*.json".format(path)) 305 | if output == "console": 306 | if board_files == None: 307 | return sum_metrics 308 | sum_metrics = [] 309 | for board_file in board_files: 310 | dashboard = parse_dashboard(board_file) 311 | board_metrics = print_dashboard_metrics(dashboard) 312 | sum_metrics += board_metrics 313 | if len(board_files) > 0: 314 | sum_metrics = sorted(list(set(sum_metrics))) 315 | logging.info(sum_metrics) 316 | else: 317 | logging.error("No dashboards found at path {}!".format(path)) 318 | else: 319 | sum_metrics = {"nodes": [], "links": []} 320 | if board_files == None: 321 | return sum_metrics 322 | for board_file in board_files: 323 | dashboard = parse_dashboard(board_file) 324 | board_metrics = data_dashboard_metrics(dashboard) 325 | sum_metrics["nodes"] += board_metrics["nodes"] 326 | sum_metrics["links"] += board_metrics["links"] 327 | 328 | return sum_metrics 329 | 330 | 331 | def metrics_all(dashboard_path, rules_path, output): 332 | if output == "json": 333 | metrics = {"nodes": [], "links": []} 334 | metrics["nodes"].append( 335 | { 336 | "id": "input", 337 | "type": "input", 338 | "name": "input", 339 | "sources": [], 340 | "targets": [], 341 | } 342 | ) 343 | metrics["nodes"].append( 344 | { 345 | "id": "output", 346 | "type": "output", 347 | "name": "output", 348 | "sources": [], 349 | "targets": [], 350 | } 351 | ) 352 | board_metrics = metrics_dashboards(dashboard_path, output) 353 | metrics["nodes"] += board_metrics["nodes"] 354 | metrics["links"] += board_metrics["links"] 355 | rule_metrics = metrics_rules(rules_path, output) 356 | metrics["nodes"] += rule_metrics["nodes"] 357 | metrics["links"] += rule_metrics["links"] 358 | metric_names = [] 359 | new_metric_names = [] 360 | final_map = {} 361 | final_nodes = [] 362 | final_links = [] 363 | for node in metrics["nodes"]: 364 | metric_names.append(node["id"]) 365 | input_links = [] 366 | for link in metrics["links"]: 367 | if link["source"] not in metric_names: 368 | metric_names.append(link["source"]) 369 | metrics["nodes"].append( 370 | { 371 | "id": link["source"], 372 | "type": "prometheus-metric", 373 | "name": link["source"], 374 | "sources": [], 375 | "targets": [], 376 | } 377 | ) 378 | input_links.append( 379 | {"source": "input", "target": link["source"], "value": 10} 380 | ) 381 | metrics["links"] += input_links 382 | i = 0 383 | for node in metrics["nodes"]: 384 | if node["id"] not in new_metric_names: 385 | final_nodes.append(node) 386 | final_map[node["id"]] = i 387 | i += 1 388 | new_metric_names.append(node["id"]) 389 | metrics["nodes"] = final_nodes 390 | """ 391 | for link in metrics['links']: 392 | link['source'] = final_map[link['source']] 393 | link['target'] = final_map[link['target']] 394 | final_links.append(link) 395 | metrics['links'] = final_links 396 | """ 397 | for link in metrics["links"]: 398 | metrics["nodes"][final_map[link["source"]]]["sources"].append( 399 | link["target"] 400 | ) 401 | metrics["nodes"][final_map[link["target"]]]["targets"].append( 402 | link["source"] 403 | ) 404 | 405 | for node in metrics["nodes"]: 406 | logging.debug( 407 | "{} {} S: {} T: {}".format( 408 | node["type"], node["id"], node["sources"], node["targets"] 409 | ) 410 | ) 411 | 412 | return json.dumps(metrics) 413 | else: 414 | out = [] 415 | metrics = metrics_rules(rules_path) + metrics_dashboards(dashboard_path) 416 | sum_metrics = sorted(list(set(metrics))) 417 | out.append("") 418 | out.append("combined-metrics:") 419 | for metric in sum_metrics: 420 | out.append("- {}".format(metric)) 421 | # for line in out: 422 | # print(line) 423 | 424 | 425 | def convert_dashboards(source_path, build_path, format, layout): 426 | board_files = glob.glob("{}/*.json".format(source_path)) 427 | for board_file in board_files: 428 | dashboard = parse_dashboard(board_file) 429 | convert_dashboard_jsonnet(dashboard, format, source_path, build_path) 430 | 431 | if len(board_files) == 0: 432 | logging.error("No dashboards found at path {}!".format(source_path)) 433 | 434 | 435 | def test_dashboards(path): 436 | board_files = glob.glob("{}/*.json".format(path)) 437 | for board_file in board_files: 438 | dashboard = parse_dashboard(board_file) 439 | logging.info("Testing dashboard `{}` ... OK".format(dashboard["_filename"])) 440 | if len(board_files) == 0: 441 | logging.error("No dashboards found at path {}!".format(path)) 442 | -------------------------------------------------------------------------------- /jsonnet_utils/prometheus_rule.py: -------------------------------------------------------------------------------- 1 | import json 2 | import yaml 3 | import os 4 | import glob 5 | import _jsonnet 6 | import logging 7 | import subprocess 8 | 9 | from .utils import parse_yaml, search_prometheus_metrics 10 | 11 | PROMETHEUS_RECORD_RULES = """ 12 | { 13 | prometheusRules+:: { 14 | groups+: [ 15 | {} 16 | ] 17 | } 18 | }""" 19 | 20 | 21 | def parse_rules(rules_file): 22 | with open(rules_file) as f: 23 | if rules_file.endswith(".yaml") or rules_file.endswith(".yml"): 24 | rule = parse_yaml(rules_file) 25 | else: 26 | rule = json.load(f) 27 | rule["_filename"] = os.path.basename(rules_file) 28 | return rule 29 | 30 | 31 | def convert_rule_jsonnet(rule, source_path, build_path): 32 | rule_lines = [] 33 | 34 | for group in rule["groups"]: 35 | rule_lines.append(json.dumps(group, indent=2)) 36 | 37 | rule_str = ( 38 | "{\nprometheusAlerts+:: {\ngroups+: [\n" + ",\n".join(rule_lines) + "\n]\n}\n}" 39 | ) 40 | 41 | if build_path == "": 42 | print(rule_str) 43 | else: 44 | filename = ( 45 | rule["_filename"].replace(".yml", ".jsonnet").replace(".yaml", ".jsonnet") 46 | ) 47 | build_file = build_path + "/" + filename 48 | with open(build_file, "w") as the_file: 49 | the_file.write(rule_str) 50 | output = ( 51 | subprocess.Popen( 52 | "jsonnet fmt -n 2 --max-blank-lines 2 --string-style s --comment-style s -i " 53 | + build_file, 54 | shell=True, 55 | stdout=subprocess.PIPE, 56 | stderr=subprocess.STDOUT, 57 | ) 58 | .stdout.read() 59 | .decode("utf-8") 60 | ) 61 | if "ERROR" in output: 62 | logging.info( 63 | "Error `{}` converting rules file `{}/{}` to `{}`.".format( 64 | output, source_path, rule["_filename"], build_file 65 | ) 66 | ) 67 | else: 68 | logging.info( 69 | "Converted rules file `{}/{}` to `{}`.".format( 70 | source_path, rule["_filename"], build_file 71 | ) 72 | ) 73 | 74 | return rule_str 75 | 76 | 77 | def print_rule_info(rule): 78 | output = [""] 79 | output.append("### File {}".format(rule.get("_filename"))) 80 | for group in rule.get("groups", []): 81 | output.append("\n#### Group {}\n".format(group["name"])) 82 | 83 | for rul in group.get("rules", []): 84 | if "record" in rul: 85 | kind = "record" 86 | else: 87 | kind = "alert" 88 | if "expr" in rul: 89 | output.append( 90 | "- **{}**: ({})".format( 91 | "**, **".join(search_prometheus_metrics(rul["expr"])), 92 | rul["expr"].replace("\n", ""), 93 | kind, 94 | ) 95 | ) 96 | return "\n".join(output) 97 | 98 | 99 | def print_rule_metrics(rule): 100 | output = [""] 101 | metrics = [] 102 | output.append("{}:".format(rule.get("_filename"))) 103 | for group in rule.get("groups", []): 104 | for rul in group.get("rules", []): 105 | if "expr" in rul: 106 | queries = search_prometheus_metrics(rul["expr"]) 107 | metrics += queries 108 | 109 | final_metrics = sorted(list(set(metrics))) 110 | for metric in final_metrics: 111 | output.append("- {}".format(metric)) 112 | for line in output: 113 | logging.debug(line) 114 | return final_metrics 115 | 116 | 117 | def data_rule_metrics(rule): 118 | data = {"nodes": [], "links": []} 119 | for group in rule.get("groups", []): 120 | for rul in group.get("rules", []): 121 | metrics = [] 122 | if "record" in rul: 123 | name = rul["record"] 124 | kind = "prometheus-record" 125 | else: 126 | name = rul["alert"] 127 | kind = "prometheus-alert" 128 | data["nodes"].append( 129 | {"id": name, "type": kind, "name": name, "sources": [], "targets": []} 130 | ) 131 | data["links"].append({"source": name, "target": "output", "value": 10}) 132 | if "expr" in rul: 133 | # if name == 'node:node_disk_utilisation:avg_irate': 134 | queries = search_prometheus_metrics(rul["expr"]) 135 | # output.append(' - {}'.format(rul['expr'])) 136 | metrics += list(set(queries)) 137 | for metric in metrics: 138 | data["links"].append({"source": metric, "target": name, "value": 10}) 139 | return data 140 | 141 | final_metrics = sorted(list(set(metrics))) 142 | for metric in final_metrics: 143 | output.append("- {}".format(metric)) 144 | for line in output: 145 | print(line) 146 | return final_metrics 147 | 148 | 149 | def info_rules(path): 150 | rule_output = [] 151 | rule_files = glob.glob("{}/*.yml".format(path)) + glob.glob( 152 | "{}/*.yaml".format(path) 153 | ) 154 | for rule_file in rule_files: 155 | rules = parse_rules(rule_file) 156 | rule_output.append(print_rule_info(rules)) 157 | if len(rule_files) == 0: 158 | logging.error("No rule definitions found at path {}!".format(path)) 159 | 160 | return "\n".join(rule_output) 161 | 162 | 163 | def metrics_rules(path, output="console"): 164 | rule_files = glob.glob("{}/*.yml".format(path)) + glob.glob( 165 | "{}/*.yaml".format(path) 166 | ) 167 | if output == "console": 168 | metrics = [] 169 | if rule_files == None: 170 | return metrics 171 | for rule_file in rule_files: 172 | rules = parse_rules(rule_file) 173 | metrics += print_rule_metrics(rules) 174 | if len(rule_files) == 0: 175 | logging.error("No rules found at path {}!".format(path)) 176 | logging.info(metrics) 177 | else: 178 | metrics = {"nodes": [], "links": []} 179 | if rule_files == None: 180 | return metrics 181 | for rule_file in rule_files: 182 | rules = parse_rules(rule_file) 183 | board_metrics = data_rule_metrics(rules) 184 | metrics["nodes"] += board_metrics["nodes"] 185 | metrics["links"] += board_metrics["links"] 186 | return metrics 187 | 188 | 189 | def convert_rules(source_path, build_path): 190 | rule_files = glob.glob("{}/*.yml".format(source_path)) + glob.glob( 191 | "{}/*.yaml".format(source_path) 192 | ) 193 | for rule_file in rule_files: 194 | rule = parse_rules(rule_file) 195 | convert_rule_jsonnet(rule, source_path, build_path) 196 | 197 | if len(rule_files) == 0: 198 | logging.error("No rules found at path {}!".format(source_path)) 199 | -------------------------------------------------------------------------------- /jsonnet_utils/utils.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import re 3 | import logging 4 | import os 5 | 6 | split_keywords = [ 7 | " / ", 8 | " + ", 9 | " * ", 10 | " - ", 11 | ">", 12 | "<", 13 | " or ", 14 | " OR ", 15 | " and ", 16 | " AND ", 17 | " unless " 18 | " UNLESS " 19 | " group_left ", 20 | " GROUP_LEFT ", 21 | " group_right ", 22 | " GROUP_RIGHT ", 23 | ] 24 | keywords = [ 25 | "-", 26 | "/", 27 | "(", 28 | ")", 29 | "!", 30 | ",", 31 | "^", 32 | ".", 33 | '"', 34 | "=", 35 | "*", 36 | "+", 37 | ">", 38 | "<", 39 | " instance ", 40 | " job ", 41 | " type ", 42 | " url ", 43 | "?:", 44 | ] 45 | 46 | final_keywords = [ 47 | "$filter", 48 | "0", 49 | "abs", 50 | "absent", 51 | "absent_over_time", 52 | "and", 53 | "acos", 54 | "acosh", 55 | "asin", 56 | "asinh", 57 | "atan", 58 | "atanh", 59 | "avg", 60 | "avg_over_time", 61 | "bool", 62 | "bottomk", 63 | "ceil", 64 | "changes", 65 | "clamp_max", 66 | "clamp_min", 67 | "cos", 68 | "cosh", 69 | "count", 70 | "count_over_time", 71 | "count_values", 72 | "d", 73 | "day_of_month", 74 | "day_of_week", 75 | "days_in_month", 76 | "deg", 77 | "delta", 78 | "deriv", 79 | "e", 80 | "exp", 81 | "floor", 82 | "group_left", 83 | "group_right", 84 | "h", 85 | "histogram_quantile", 86 | "holt_winters", 87 | "hour", 88 | "idelta", 89 | "increase", 90 | "inf", 91 | "irate", 92 | "json", 93 | "label_join", 94 | "label_replace", 95 | "last_over_time", 96 | "ln", 97 | "log10", 98 | "log2", 99 | "m", 100 | "max", 101 | "max_over_time", 102 | "min", 103 | "min_over_time", 104 | "minute", 105 | "month", 106 | "offset", 107 | "or", 108 | "pi", 109 | "predict_linear", 110 | "present_over_time", 111 | "quantile_over_time", 112 | "rad", 113 | "rate", 114 | "resets", 115 | "round", 116 | "s", 117 | "scalar", 118 | "sgn", 119 | "sin", 120 | "sinh", 121 | "sort", 122 | "sort_desc", 123 | "sqrt", 124 | "stddev", 125 | "stddev_over_time", 126 | "stdvar", 127 | "stdvar_over_time", 128 | "sum", 129 | "tan", 130 | "tanh", 131 | "time", 132 | "timestamp", 133 | "topk", 134 | "vector", 135 | "w", 136 | "y", 137 | "year", 138 | "|", 139 | "$", 140 | ] 141 | 142 | 143 | def parse_yaml(yaml_file): 144 | with open(yaml_file) as f: 145 | try: 146 | data = yaml.load(f, Loader=yaml.FullLoader) 147 | except AttributeError: 148 | data = yaml.load(f) 149 | return data 150 | 151 | 152 | def split_by_keyword(query, split_keywords, level=0): 153 | if level < len(split_keywords): 154 | new_query = [] 155 | for item in query: 156 | new_query = new_query + item.split(split_keywords[level]) 157 | return split_by_keyword(new_query, split_keywords, level + 1) 158 | 159 | else: 160 | return query 161 | 162 | 163 | def clean_comments(query): 164 | lines = query.splitlines() 165 | output_lines = [] 166 | for line in lines: 167 | line = line.strip() 168 | if not line.startswith("#"): 169 | output_lines.append(line) 170 | return " ".join(output_lines) 171 | 172 | def is_debug_active(): 173 | 174 | debug = os.environ.get("DEBUG", False) 175 | if debug.lower() == 'false' or debug == 0: 176 | debug = False 177 | if debug != False: 178 | debug = True 179 | return debug 180 | 181 | def search_prometheus_metrics(orig_query): 182 | query = clean_comments(orig_query) 183 | query = re.sub(r"[0-9]+e[0-9]+", "", query) 184 | query = query.replace(" [0-9]+ ", "") 185 | query = re.sub( 186 | r"group_left \((\w|,| )+\)", " group_left ", query, flags=re.IGNORECASE 187 | ) 188 | query = re.sub( 189 | r"group_left\((\w|,| )+\)", " group_left ", query, flags=re.IGNORECASE 190 | ) 191 | query = re.sub( 192 | r"group_right \((\w|,| )+\)", " group_right ", query, flags=re.IGNORECASE 193 | ) 194 | query = re.sub( 195 | r"group_right\((\w|,| )+\)", " group_right ", query, flags=re.IGNORECASE 196 | ) 197 | 198 | subqueries = split_by_keyword([query], split_keywords, 0) 199 | 200 | logging.debug("Step 1: {}".format(query)) 201 | subquery_output = [] 202 | for subquery in subqueries: 203 | subquery = re.sub(r"\{.*\}", "", subquery) 204 | subquery = re.sub(r"\[.*\]", "", subquery) 205 | subquery = re.sub(r"\".*\"", "", subquery) 206 | 207 | subquery = re.sub(r"by \((\w|,| )+\)", "", subquery, flags=re.IGNORECASE) 208 | subquery = re.sub(r"by\((\w|,| )+\)", "", subquery, flags=re.IGNORECASE) 209 | subquery = re.sub(r"on \((\w|,| )+\)", "", subquery, flags=re.IGNORECASE) 210 | subquery = re.sub(r"on\((\w|,| )+\)", "", subquery, flags=re.IGNORECASE) 211 | subquery = re.sub(r"without \(.*\)", "", subquery, flags=re.IGNORECASE) 212 | subquery = re.sub(r"without\(.*\)", "", subquery, flags=re.IGNORECASE) 213 | subquery_output.append(subquery) 214 | query = " ".join(subquery_output) 215 | 216 | logging.debug("Step 2: {}".format(query)) 217 | for keyword in keywords: 218 | query = query.replace(keyword, " ") 219 | query = re.sub(r" [0-9]+ ", " ", query) 220 | query = re.sub(r" [0-9]+", " ", query) 221 | query = re.sub(r"^[0-9]+$", " ", query) 222 | query = query.replace("(", " ") 223 | final_queries = [] 224 | 225 | logging.debug("Step 3: {}".format(query)) 226 | raw_queries = query.split(" ") 227 | for raw_query in raw_queries: 228 | if raw_query.lower().strip() not in final_keywords: 229 | raw_query = re.sub(r"^[0-9]+$", " ", raw_query) 230 | if raw_query.strip() != "": 231 | final_queries.append(raw_query.strip()) 232 | 233 | output = list(set(final_queries)) 234 | 235 | #logging.debug("Parsed query: {}".format(orig_query)) 236 | logging.debug("Found metrics: {}".format(output)) 237 | return output 238 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | 2 | Click 3 | jsonnet==0.12.1 4 | requests 5 | pyyaml 6 | -------------------------------------------------------------------------------- /scripts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cznewt/jsonnet-utils/cf77802278b1d96e6e612987f18a57261329692f/scripts/.gitkeep -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cznewt/jsonnet-utils/cf77802278b1d96e6e612987f18a57261329692f/scripts/test.sh -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='jsonnet_utils', 5 | version='0.3', 6 | packages=find_packages(), 7 | include_package_data=True, 8 | install_requires=[ 9 | 'Click', 10 | ], 11 | entry_points=''' 12 | [console_scripts] 13 | jsonnet-utils-all-metrics=jsonnet_utils.cli:all_metrics 14 | jsonnet-utils-grafana-metrics=jsonnet_utils.cli:dashboard_metrics 15 | jsonnet-utils-prometheus-metrics=jsonnet_utils.cli:rule_metrics 16 | jsonnet-utils-grafana-convert=jsonnet_utils.cli:dashboard_convert 17 | jsonnet-utils-prometheus-convert=jsonnet_utils.cli:rule_convert 18 | jsonnet-utils-grafana-info=jsonnet_utils.cli:dashboard_info 19 | jsonnet-utils-prometheus-info=jsonnet_utils.cli:rule_info 20 | jsonnet-utils-grafana-test=jsonnet_utils.cli:dashboard_test 21 | ''', 22 | ) 23 | -------------------------------------------------------------------------------- /tests/source/prometheus-redis_rev1.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_PROM", 5 | "label": "prom", 6 | "description": "Prometheus Data Source", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "panel", 15 | "id": "singlestat", 16 | "name": "Singlestat", 17 | "version": "" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "" 24 | }, 25 | { 26 | "type": "grafana", 27 | "id": "grafana", 28 | "name": "Grafana", 29 | "version": "3.1.1" 30 | }, 31 | { 32 | "type": "datasource", 33 | "id": "prometheus", 34 | "name": "Prometheus", 35 | "version": "1.0.0" 36 | } 37 | ], 38 | "id": null, 39 | "title": "Prometheus Redis", 40 | "description": "Prometheus dashboard for Redis servers", 41 | "tags": [ 42 | "prometheus", 43 | "redis" 44 | ], 45 | "style": "dark", 46 | "timezone": "browser", 47 | "editable": true, 48 | "hideControls": false, 49 | "sharedCrosshair": false, 50 | "rows": [ 51 | { 52 | "collapse": false, 53 | "editable": true, 54 | "height": "250px", 55 | "panels": [ 56 | { 57 | "cacheTimeout": null, 58 | "colorBackground": false, 59 | "colorValue": false, 60 | "colors": [ 61 | "rgba(245, 54, 54, 0.9)", 62 | "rgba(237, 129, 40, 0.89)", 63 | "rgba(50, 172, 45, 0.97)" 64 | ], 65 | "datasource": "${DS_PROM}", 66 | "decimals": 0, 67 | "editable": true, 68 | "error": false, 69 | "format": "s", 70 | "gauge": { 71 | "maxValue": 100, 72 | "minValue": 0, 73 | "show": false, 74 | "thresholdLabels": false, 75 | "thresholdMarkers": true 76 | }, 77 | "id": 9, 78 | "interval": null, 79 | "isNew": true, 80 | "links": [], 81 | "mappingType": 1, 82 | "mappingTypes": [ 83 | { 84 | "name": "value to text", 85 | "value": 1 86 | }, 87 | { 88 | "name": "range to text", 89 | "value": 2 90 | } 91 | ], 92 | "maxDataPoints": 100, 93 | "nullPointMode": "connected", 94 | "nullText": null, 95 | "postfix": "", 96 | "postfixFontSize": "50%", 97 | "prefix": "", 98 | "prefixFontSize": "50%", 99 | "rangeMaps": [ 100 | { 101 | "from": "null", 102 | "text": "N/A", 103 | "to": "null" 104 | } 105 | ], 106 | "span": 1, 107 | "sparkline": { 108 | "fillColor": "rgba(31, 118, 189, 0.18)", 109 | "full": false, 110 | "lineColor": "rgb(31, 120, 193)", 111 | "show": false 112 | }, 113 | "targets": [ 114 | { 115 | "expr": "redis_uptime_in_seconds{addr=\"$addr\"}", 116 | "intervalFactor": 2, 117 | "legendFormat": "", 118 | "metric": "", 119 | "refId": "A", 120 | "step": 1800 121 | } 122 | ], 123 | "thresholds": "", 124 | "title": "Uptime", 125 | "type": "singlestat", 126 | "valueFontSize": "70%", 127 | "valueMaps": [ 128 | { 129 | "op": "=", 130 | "text": "N/A", 131 | "value": "null" 132 | } 133 | ], 134 | "valueName": "avg" 135 | }, 136 | { 137 | "cacheTimeout": null, 138 | "colorBackground": false, 139 | "colorValue": false, 140 | "colors": [ 141 | "rgba(245, 54, 54, 0.9)", 142 | "rgba(237, 129, 40, 0.89)", 143 | "rgba(50, 172, 45, 0.97)" 144 | ], 145 | "datasource": "${DS_PROM}", 146 | "decimals": 0, 147 | "editable": true, 148 | "error": false, 149 | "format": "none", 150 | "gauge": { 151 | "maxValue": 100, 152 | "minValue": 0, 153 | "show": false, 154 | "thresholdLabels": false, 155 | "thresholdMarkers": true 156 | }, 157 | "hideTimeOverride": true, 158 | "id": 12, 159 | "interval": null, 160 | "isNew": true, 161 | "links": [], 162 | "mappingType": 1, 163 | "mappingTypes": [ 164 | { 165 | "name": "value to text", 166 | "value": 1 167 | }, 168 | { 169 | "name": "range to text", 170 | "value": 2 171 | } 172 | ], 173 | "maxDataPoints": 100, 174 | "nullPointMode": "connected", 175 | "nullText": null, 176 | "postfix": "", 177 | "postfixFontSize": "50%", 178 | "prefix": "", 179 | "prefixFontSize": "50%", 180 | "rangeMaps": [ 181 | { 182 | "from": "null", 183 | "text": "N/A", 184 | "to": "null" 185 | } 186 | ], 187 | "span": 1, 188 | "sparkline": { 189 | "fillColor": "rgba(31, 118, 189, 0.18)", 190 | "full": false, 191 | "lineColor": "rgb(31, 120, 193)", 192 | "show": true 193 | }, 194 | "targets": [ 195 | { 196 | "expr": "redis_connected_clients{addr=\"$addr\"}", 197 | "intervalFactor": 2, 198 | "legendFormat": "", 199 | "metric": "", 200 | "refId": "A", 201 | "step": 2 202 | } 203 | ], 204 | "thresholds": "", 205 | "timeFrom": "1m", 206 | "timeShift": null, 207 | "title": "Clients", 208 | "type": "singlestat", 209 | "valueFontSize": "80%", 210 | "valueMaps": [ 211 | { 212 | "op": "=", 213 | "text": "N/A", 214 | "value": "null" 215 | } 216 | ], 217 | "valueName": "current" 218 | }, 219 | { 220 | "cacheTimeout": null, 221 | "colorBackground": false, 222 | "colorValue": false, 223 | "colors": [ 224 | "rgba(50, 172, 45, 0.97)", 225 | "rgba(237, 129, 40, 0.89)", 226 | "rgba(245, 54, 54, 0.9)" 227 | ], 228 | "datasource": "${DS_PROM}", 229 | "decimals": 0, 230 | "editable": true, 231 | "error": false, 232 | "format": "percent", 233 | "gauge": { 234 | "maxValue": 100, 235 | "minValue": 0, 236 | "show": true, 237 | "thresholdLabels": false, 238 | "thresholdMarkers": true 239 | }, 240 | "hideTimeOverride": true, 241 | "id": 11, 242 | "interval": null, 243 | "isNew": true, 244 | "links": [], 245 | "mappingType": 1, 246 | "mappingTypes": [ 247 | { 248 | "name": "value to text", 249 | "value": 1 250 | }, 251 | { 252 | "name": "range to text", 253 | "value": 2 254 | } 255 | ], 256 | "maxDataPoints": 100, 257 | "nullPointMode": "connected", 258 | "nullText": null, 259 | "postfix": "", 260 | "postfixFontSize": "50%", 261 | "prefix": "", 262 | "prefixFontSize": "50%", 263 | "rangeMaps": [ 264 | { 265 | "from": "null", 266 | "text": "N/A", 267 | "to": "null" 268 | } 269 | ], 270 | "span": 2, 271 | "sparkline": { 272 | "fillColor": "rgba(31, 118, 189, 0.18)", 273 | "full": false, 274 | "lineColor": "rgb(31, 120, 193)", 275 | "show": true 276 | }, 277 | "targets": [ 278 | { 279 | "expr": "100 * (redis_memory_used_bytes{addr=~\"$addr\"} / redis_config_maxmemory{addr=~\"$addr\"} )", 280 | "intervalFactor": 2, 281 | "legendFormat": "", 282 | "metric": "", 283 | "refId": "A", 284 | "step": 2 285 | } 286 | ], 287 | "thresholds": "80,95", 288 | "timeFrom": "1m", 289 | "timeShift": null, 290 | "title": "Memory Usage", 291 | "type": "singlestat", 292 | "valueFontSize": "80%", 293 | "valueMaps": [ 294 | { 295 | "op": "=", 296 | "text": "N/A", 297 | "value": "null" 298 | } 299 | ], 300 | "valueName": "current" 301 | }, 302 | { 303 | "aliasColors": {}, 304 | "bars": false, 305 | "datasource": "${DS_PROM}", 306 | "editable": true, 307 | "error": false, 308 | "fill": 1, 309 | "grid": { 310 | "threshold1": null, 311 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 312 | "threshold2": null, 313 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 314 | }, 315 | "id": 2, 316 | "isNew": true, 317 | "legend": { 318 | "avg": false, 319 | "current": false, 320 | "max": false, 321 | "min": false, 322 | "show": false, 323 | "total": false, 324 | "values": false 325 | }, 326 | "lines": true, 327 | "linewidth": 2, 328 | "links": [], 329 | "nullPointMode": "connected", 330 | "percentage": false, 331 | "pointradius": 5, 332 | "points": false, 333 | "renderer": "flot", 334 | "seriesOverrides": [], 335 | "span": 4, 336 | "stack": false, 337 | "steppedLine": false, 338 | "targets": [ 339 | { 340 | "expr": "rate(redis_commands_processed_total{addr=~\"$addr\"}[5m])", 341 | "interval": "", 342 | "intervalFactor": 2, 343 | "legendFormat": "", 344 | "metric": "A", 345 | "refId": "A", 346 | "step": 240, 347 | "target": "" 348 | } 349 | ], 350 | "timeFrom": null, 351 | "timeShift": null, 352 | "title": "Commands Executed / sec", 353 | "tooltip": { 354 | "msResolution": false, 355 | "shared": true, 356 | "sort": 0, 357 | "value_type": "cumulative" 358 | }, 359 | "type": "graph", 360 | "xaxis": { 361 | "show": true 362 | }, 363 | "yaxes": [ 364 | { 365 | "format": "short", 366 | "label": null, 367 | "logBase": 1, 368 | "max": null, 369 | "min": null, 370 | "show": true 371 | }, 372 | { 373 | "format": "short", 374 | "label": null, 375 | "logBase": 1, 376 | "max": null, 377 | "min": null, 378 | "show": true 379 | } 380 | ] 381 | }, 382 | { 383 | "aliasColors": {}, 384 | "bars": false, 385 | "datasource": "${DS_PROM}", 386 | "decimals": 2, 387 | "editable": true, 388 | "error": false, 389 | "fill": 1, 390 | "grid": { 391 | "threshold1": null, 392 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 393 | "threshold2": null, 394 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 395 | }, 396 | "id": 1, 397 | "isNew": true, 398 | "legend": { 399 | "avg": false, 400 | "current": false, 401 | "max": false, 402 | "min": false, 403 | "show": false, 404 | "total": false, 405 | "values": false 406 | }, 407 | "lines": true, 408 | "linewidth": 2, 409 | "links": [], 410 | "nullPointMode": "connected", 411 | "percentage": true, 412 | "pointradius": 5, 413 | "points": false, 414 | "renderer": "flot", 415 | "seriesOverrides": [], 416 | "span": 4, 417 | "stack": false, 418 | "steppedLine": false, 419 | "targets": [ 420 | { 421 | "expr": "irate(redis_keyspace_hits_total{addr=\"$addr\"}[5m])", 422 | "hide": false, 423 | "interval": "", 424 | "intervalFactor": 2, 425 | "legendFormat": "hits", 426 | "metric": "", 427 | "refId": "A", 428 | "step": 240, 429 | "target": "" 430 | }, 431 | { 432 | "expr": "irate(redis_keyspace_misses_total{addr=\"$addr\"}[5m])", 433 | "hide": false, 434 | "interval": "", 435 | "intervalFactor": 2, 436 | "legendFormat": "misses", 437 | "metric": "", 438 | "refId": "B", 439 | "step": 240, 440 | "target": "" 441 | } 442 | ], 443 | "timeFrom": null, 444 | "timeShift": null, 445 | "title": "Hits / Misses per Sec", 446 | "tooltip": { 447 | "msResolution": false, 448 | "shared": true, 449 | "sort": 0, 450 | "value_type": "individual" 451 | }, 452 | "type": "graph", 453 | "xaxis": { 454 | "show": true 455 | }, 456 | "yaxes": [ 457 | { 458 | "format": "short", 459 | "label": "", 460 | "logBase": 1, 461 | "max": null, 462 | "min": 0, 463 | "show": true 464 | }, 465 | { 466 | "format": "short", 467 | "label": null, 468 | "logBase": 1, 469 | "max": null, 470 | "min": null, 471 | "show": true 472 | } 473 | ] 474 | } 475 | ], 476 | "title": "Row" 477 | }, 478 | { 479 | "collapse": false, 480 | "editable": true, 481 | "height": "250px", 482 | "panels": [ 483 | { 484 | "aliasColors": { 485 | "max": "#BF1B00" 486 | }, 487 | "bars": false, 488 | "datasource": "${DS_PROM}", 489 | "editable": true, 490 | "error": false, 491 | "fill": 1, 492 | "grid": { 493 | "threshold1": null, 494 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 495 | "threshold2": null, 496 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 497 | }, 498 | "id": 7, 499 | "isNew": true, 500 | "legend": { 501 | "avg": false, 502 | "current": false, 503 | "hideEmpty": false, 504 | "hideZero": false, 505 | "max": false, 506 | "min": false, 507 | "show": true, 508 | "total": false, 509 | "values": false 510 | }, 511 | "lines": true, 512 | "linewidth": 2, 513 | "links": [], 514 | "nullPointMode": "null as zero", 515 | "percentage": false, 516 | "pointradius": 5, 517 | "points": false, 518 | "renderer": "flot", 519 | "seriesOverrides": [], 520 | "span": 6, 521 | "stack": false, 522 | "steppedLine": false, 523 | "targets": [ 524 | { 525 | "expr": "redis_memory_used_bytes{addr=~\"$addr\"} ", 526 | "intervalFactor": 2, 527 | "legendFormat": "used", 528 | "metric": "", 529 | "refId": "A", 530 | "step": 240, 531 | "target": "" 532 | }, 533 | { 534 | "expr": "redis_config_maxmemory{addr=~\"$addr\"} ", 535 | "hide": false, 536 | "intervalFactor": 2, 537 | "legendFormat": "max", 538 | "refId": "B", 539 | "step": 240 540 | } 541 | ], 542 | "timeFrom": null, 543 | "timeShift": null, 544 | "title": "Total Memory Usage", 545 | "tooltip": { 546 | "msResolution": false, 547 | "shared": true, 548 | "sort": 0, 549 | "value_type": "cumulative" 550 | }, 551 | "type": "graph", 552 | "xaxis": { 553 | "show": true 554 | }, 555 | "yaxes": [ 556 | { 557 | "format": "bytes", 558 | "label": null, 559 | "logBase": 1, 560 | "max": null, 561 | "min": 0, 562 | "show": true 563 | }, 564 | { 565 | "format": "short", 566 | "label": null, 567 | "logBase": 1, 568 | "max": null, 569 | "min": null, 570 | "show": true 571 | } 572 | ] 573 | }, 574 | { 575 | "aliasColors": {}, 576 | "bars": false, 577 | "datasource": "${DS_PROM}", 578 | "editable": true, 579 | "error": false, 580 | "fill": 1, 581 | "grid": { 582 | "threshold1": null, 583 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 584 | "threshold2": null, 585 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 586 | }, 587 | "id": 10, 588 | "isNew": true, 589 | "legend": { 590 | "avg": false, 591 | "current": false, 592 | "max": false, 593 | "min": false, 594 | "show": true, 595 | "total": false, 596 | "values": false 597 | }, 598 | "lines": true, 599 | "linewidth": 2, 600 | "links": [], 601 | "nullPointMode": "connected", 602 | "percentage": false, 603 | "pointradius": 5, 604 | "points": false, 605 | "renderer": "flot", 606 | "seriesOverrides": [], 607 | "span": 6, 608 | "stack": false, 609 | "steppedLine": false, 610 | "targets": [ 611 | { 612 | "expr": "rate(redis_net_input_bytes_total{addr=\"$addr\"}[5m])", 613 | "intervalFactor": 2, 614 | "legendFormat": "{{ input }}", 615 | "refId": "A", 616 | "step": 240 617 | }, 618 | { 619 | "expr": "rate(redis_net_output_bytes_total{addr=\"$addr\"}[5m])", 620 | "interval": "", 621 | "intervalFactor": 2, 622 | "legendFormat": "{{ output }}", 623 | "refId": "B", 624 | "step": 240 625 | } 626 | ], 627 | "timeFrom": null, 628 | "timeShift": null, 629 | "title": "Network I/O", 630 | "tooltip": { 631 | "msResolution": true, 632 | "shared": true, 633 | "sort": 0, 634 | "value_type": "cumulative" 635 | }, 636 | "type": "graph", 637 | "xaxis": { 638 | "show": true 639 | }, 640 | "yaxes": [ 641 | { 642 | "format": "bytes", 643 | "label": null, 644 | "logBase": 1, 645 | "max": null, 646 | "min": null, 647 | "show": true 648 | }, 649 | { 650 | "format": "short", 651 | "label": null, 652 | "logBase": 1, 653 | "max": null, 654 | "min": null, 655 | "show": true 656 | } 657 | ] 658 | } 659 | ], 660 | "title": "New row" 661 | }, 662 | { 663 | "collapse": false, 664 | "editable": true, 665 | "height": "250px", 666 | "panels": [ 667 | { 668 | "aliasColors": {}, 669 | "bars": false, 670 | "datasource": "${DS_PROM}", 671 | "editable": true, 672 | "error": false, 673 | "fill": 7, 674 | "grid": { 675 | "threshold1": null, 676 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 677 | "threshold2": null, 678 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 679 | }, 680 | "id": 5, 681 | "isNew": true, 682 | "legend": { 683 | "alignAsTable": true, 684 | "avg": false, 685 | "current": true, 686 | "max": false, 687 | "min": false, 688 | "rightSide": true, 689 | "show": true, 690 | "total": false, 691 | "values": true 692 | }, 693 | "lines": true, 694 | "linewidth": 2, 695 | "links": [], 696 | "nullPointMode": "connected", 697 | "percentage": false, 698 | "pointradius": 5, 699 | "points": false, 700 | "renderer": "flot", 701 | "seriesOverrides": [], 702 | "span": 6, 703 | "stack": true, 704 | "steppedLine": false, 705 | "targets": [ 706 | { 707 | "expr": "sum (redis_db_keys{addr=~\"$addr\"}) by (db)", 708 | "interval": "", 709 | "intervalFactor": 2, 710 | "legendFormat": "{{ db }} ", 711 | "refId": "A", 712 | "step": 240, 713 | "target": "" 714 | } 715 | ], 716 | "timeFrom": null, 717 | "timeShift": null, 718 | "title": "Total Items per DB", 719 | "tooltip": { 720 | "msResolution": false, 721 | "shared": true, 722 | "sort": 0, 723 | "value_type": "individual" 724 | }, 725 | "type": "graph", 726 | "xaxis": { 727 | "show": true 728 | }, 729 | "yaxes": [ 730 | { 731 | "format": "none", 732 | "label": null, 733 | "logBase": 1, 734 | "max": null, 735 | "min": null, 736 | "show": true 737 | }, 738 | { 739 | "format": "short", 740 | "label": null, 741 | "logBase": 1, 742 | "max": null, 743 | "min": null, 744 | "show": true 745 | } 746 | ] 747 | }, 748 | { 749 | "aliasColors": {}, 750 | "bars": false, 751 | "datasource": "${DS_PROM}", 752 | "editable": true, 753 | "error": false, 754 | "fill": 7, 755 | "grid": { 756 | "threshold1": null, 757 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 758 | "threshold2": null, 759 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 760 | }, 761 | "id": 13, 762 | "isNew": true, 763 | "legend": { 764 | "avg": false, 765 | "current": false, 766 | "max": false, 767 | "min": false, 768 | "show": true, 769 | "total": false, 770 | "values": false 771 | }, 772 | "lines": true, 773 | "linewidth": 2, 774 | "links": [], 775 | "nullPointMode": "connected", 776 | "percentage": false, 777 | "pointradius": 5, 778 | "points": false, 779 | "renderer": "flot", 780 | "seriesOverrides": [], 781 | "span": 6, 782 | "stack": true, 783 | "steppedLine": false, 784 | "targets": [ 785 | { 786 | "expr": "sum (redis_db_keys{addr=~\"$addr\"}) - sum (redis_db_keys_expiring{addr=~\"$addr\"}) ", 787 | "interval": "", 788 | "intervalFactor": 2, 789 | "legendFormat": "not expiring", 790 | "refId": "A", 791 | "step": 240, 792 | "target": "" 793 | }, 794 | { 795 | "expr": "sum (redis_db_keys_expiring{addr=~\"$addr\"}) ", 796 | "interval": "", 797 | "intervalFactor": 2, 798 | "legendFormat": "expiring", 799 | "metric": "", 800 | "refId": "B", 801 | "step": 240 802 | } 803 | ], 804 | "timeFrom": null, 805 | "timeShift": null, 806 | "title": "Expiring vs Not-Expiring Keys", 807 | "tooltip": { 808 | "msResolution": false, 809 | "shared": true, 810 | "sort": 0, 811 | "value_type": "individual" 812 | }, 813 | "type": "graph", 814 | "xaxis": { 815 | "show": true 816 | }, 817 | "yaxes": [ 818 | { 819 | "format": "short", 820 | "label": null, 821 | "logBase": 1, 822 | "max": null, 823 | "min": null, 824 | "show": true 825 | }, 826 | { 827 | "format": "short", 828 | "label": null, 829 | "logBase": 1, 830 | "max": null, 831 | "min": null, 832 | "show": true 833 | } 834 | ] 835 | }, 836 | { 837 | "aliasColors": { 838 | "evicts": "#890F02", 839 | "memcached_items_evicted_total{instance=\"172.17.0.1:9150\",job=\"prometheus\"}": "#890F02", 840 | "reclaims": "#3F6833" 841 | }, 842 | "bars": false, 843 | "datasource": "${DS_PROM}", 844 | "editable": true, 845 | "error": false, 846 | "fill": 1, 847 | "grid": { 848 | "threshold1": null, 849 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 850 | "threshold2": null, 851 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 852 | }, 853 | "id": 8, 854 | "isNew": true, 855 | "legend": { 856 | "avg": false, 857 | "current": false, 858 | "max": false, 859 | "min": false, 860 | "show": true, 861 | "total": false, 862 | "values": false 863 | }, 864 | "lines": true, 865 | "linewidth": 2, 866 | "links": [], 867 | "nullPointMode": "connected", 868 | "percentage": false, 869 | "pointradius": 5, 870 | "points": false, 871 | "renderer": "flot", 872 | "seriesOverrides": [ 873 | { 874 | "alias": "reclaims", 875 | "yaxis": 2 876 | } 877 | ], 878 | "span": 6, 879 | "stack": false, 880 | "steppedLine": false, 881 | "targets": [ 882 | { 883 | "expr": "sum(rate(redis_expired_keys_total{addr=~\"$addr\"}[5m])) by (addr)", 884 | "interval": "", 885 | "intervalFactor": 2, 886 | "legendFormat": "expired", 887 | "metric": "", 888 | "refId": "A", 889 | "step": 240, 890 | "target": "" 891 | }, 892 | { 893 | "expr": "sum(rate(redis_evicted_keys_total{addr=~\"$addr\"}[5m])) by (addr)", 894 | "interval": "", 895 | "intervalFactor": 2, 896 | "legendFormat": "evicted", 897 | "refId": "B", 898 | "step": 240 899 | } 900 | ], 901 | "timeFrom": null, 902 | "timeShift": null, 903 | "title": "Expired / Evicted", 904 | "tooltip": { 905 | "msResolution": false, 906 | "shared": true, 907 | "sort": 0, 908 | "value_type": "cumulative" 909 | }, 910 | "type": "graph", 911 | "xaxis": { 912 | "show": true 913 | }, 914 | "yaxes": [ 915 | { 916 | "format": "short", 917 | "label": null, 918 | "logBase": 1, 919 | "max": null, 920 | "min": null, 921 | "show": true 922 | }, 923 | { 924 | "format": "short", 925 | "label": null, 926 | "logBase": 1, 927 | "max": null, 928 | "min": null, 929 | "show": true 930 | } 931 | ] 932 | }, 933 | { 934 | "aliasColors": {}, 935 | "bars": false, 936 | "datasource": "${DS_PROM}", 937 | "editable": true, 938 | "error": false, 939 | "fill": 8, 940 | "grid": { 941 | "threshold1": null, 942 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 943 | "threshold2": null, 944 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 945 | }, 946 | "id": 14, 947 | "isNew": true, 948 | "legend": { 949 | "avg": false, 950 | "current": false, 951 | "max": false, 952 | "min": false, 953 | "show": true, 954 | "total": false, 955 | "values": false 956 | }, 957 | "lines": true, 958 | "linewidth": 1, 959 | "links": [], 960 | "nullPointMode": "connected", 961 | "percentage": false, 962 | "pointradius": 5, 963 | "points": false, 964 | "renderer": "flot", 965 | "seriesOverrides": [], 966 | "span": 6, 967 | "stack": true, 968 | "steppedLine": false, 969 | "targets": [ 970 | { 971 | "expr": "topk(5, irate(redis_command_call_duration_seconds_count{addr=~\"$addr\"} [1m]))", 972 | "interval": "", 973 | "intervalFactor": 2, 974 | "legendFormat": "{{ cmd }}", 975 | "metric": "redis_command_calls_total", 976 | "refId": "A", 977 | "step": 240 978 | } 979 | ], 980 | "timeFrom": null, 981 | "timeShift": null, 982 | "title": "Command Calls / sec", 983 | "tooltip": { 984 | "msResolution": true, 985 | "shared": true, 986 | "sort": 0, 987 | "value_type": "cumulative" 988 | }, 989 | "type": "graph", 990 | "xaxis": { 991 | "show": true 992 | }, 993 | "yaxes": [ 994 | { 995 | "format": "short", 996 | "label": null, 997 | "logBase": 1, 998 | "max": null, 999 | "min": null, 1000 | "show": true 1001 | }, 1002 | { 1003 | "format": "short", 1004 | "label": null, 1005 | "logBase": 1, 1006 | "max": null, 1007 | "min": null, 1008 | "show": true 1009 | } 1010 | ] 1011 | } 1012 | ], 1013 | "title": "New row" 1014 | } 1015 | ], 1016 | "time": { 1017 | "from": "now-24h", 1018 | "to": "now" 1019 | }, 1020 | "timepicker": { 1021 | "refresh_intervals": [ 1022 | "5s", 1023 | "10s", 1024 | "30s", 1025 | "1m", 1026 | "5m", 1027 | "15m", 1028 | "30m", 1029 | "1h", 1030 | "2h", 1031 | "1d" 1032 | ], 1033 | "time_options": [ 1034 | "5m", 1035 | "15m", 1036 | "1h", 1037 | "6h", 1038 | "12h", 1039 | "24h", 1040 | "2d", 1041 | "7d", 1042 | "30d" 1043 | ] 1044 | }, 1045 | "templating": { 1046 | "list": [ 1047 | { 1048 | "current": {}, 1049 | "datasource": "${DS_PROM}", 1050 | "hide": 0, 1051 | "includeAll": false, 1052 | "multi": false, 1053 | "name": "addr", 1054 | "options": [], 1055 | "query": "label_values(redis_connected_clients, addr)", 1056 | "refresh": 1, 1057 | "regex": "", 1058 | "type": "query" 1059 | } 1060 | ] 1061 | }, 1062 | "annotations": { 1063 | "list": [] 1064 | }, 1065 | "refresh": "30s", 1066 | "schemaVersion": 12, 1067 | "version": 52, 1068 | "links": [], 1069 | "gnetId": 763 1070 | } -------------------------------------------------------------------------------- /tests/source/server-single_rev3.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_SERVERMONITOR", 5 | "label": "servermonitor", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "influxdb", 9 | "pluginName": "InfluxDB" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "4.1.1" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "influxdb", 28 | "name": "InfluxDB", 29 | "version": "1.0.0" 30 | } 31 | ], 32 | "annotations": { 33 | "list": [] 34 | }, 35 | "editable": true, 36 | "gnetId": 1375, 37 | "graphTooltip": 0, 38 | "hideControls": true, 39 | "id": null, 40 | "links": [], 41 | "refresh": false, 42 | "rows": [ 43 | { 44 | "collapse": false, 45 | "height": 228, 46 | "panels": [ 47 | { 48 | "aliasColors": { 49 | "undefined": "#1F78C1" 50 | }, 51 | "bars": false, 52 | "datasource": "${DS_SERVERMONITOR}", 53 | "decimals": null, 54 | "editable": true, 55 | "error": false, 56 | "fill": 0, 57 | "id": 10, 58 | "legend": { 59 | "avg": false, 60 | "current": false, 61 | "max": false, 62 | "min": false, 63 | "show": true, 64 | "total": false, 65 | "values": false 66 | }, 67 | "lines": true, 68 | "linewidth": 2, 69 | "links": [], 70 | "minSpan": 2, 71 | "nullPointMode": "connected", 72 | "percentage": false, 73 | "pointradius": 3, 74 | "points": false, 75 | "renderer": "flot", 76 | "repeat": null, 77 | "seriesOverrides": [ 78 | { 79 | "alias": "/^inodes.*/i", 80 | "color": "#82B5D8", 81 | "yaxis": 2 82 | }, 83 | { 84 | "alias": "/^space.*/i", 85 | "color": "#F4D598" 86 | }, 87 | { 88 | "alias": "/^space: Total.*/i", 89 | "fillBelowTo": "space: free, /", 90 | "lines": false 91 | }, 92 | { 93 | "alias": "/^inodes: total.*/i", 94 | "fillBelowTo": "inodes: free, /", 95 | "lines": false 96 | }, 97 | { 98 | "alias": "/^space: free.*/i", 99 | "fill": 8, 100 | "linewidth": 4 101 | }, 102 | { 103 | "alias": "/^inodes: free.*/i", 104 | "linewidth": 4 105 | } 106 | ], 107 | "span": 4, 108 | "stack": false, 109 | "steppedLine": false, 110 | "targets": [ 111 | { 112 | "alias": "space: Total, $tag_path", 113 | "dsType": "influxdb", 114 | "groupBy": [ 115 | { 116 | "params": [ 117 | "$interval" 118 | ], 119 | "type": "time" 120 | }, 121 | { 122 | "params": [ 123 | "path" 124 | ], 125 | "type": "tag" 126 | }, 127 | { 128 | "params": [ 129 | "null" 130 | ], 131 | "type": "fill" 132 | } 133 | ], 134 | "measurement": "disk", 135 | "policy": "default", 136 | "refId": "A", 137 | "resultFormat": "time_series", 138 | "select": [ 139 | [ 140 | { 141 | "params": [ 142 | "total" 143 | ], 144 | "type": "field" 145 | }, 146 | { 147 | "params": [], 148 | "type": "mean" 149 | } 150 | ] 151 | ], 152 | "tags": [ 153 | { 154 | "key": "host", 155 | "operator": "=~", 156 | "value": "/^$host$/" 157 | } 158 | ] 159 | }, 160 | { 161 | "alias": "space: free, $tag_path", 162 | "dsType": "influxdb", 163 | "groupBy": [ 164 | { 165 | "params": [ 166 | "$interval" 167 | ], 168 | "type": "time" 169 | }, 170 | { 171 | "params": [ 172 | "path" 173 | ], 174 | "type": "tag" 175 | }, 176 | { 177 | "params": [ 178 | "null" 179 | ], 180 | "type": "fill" 181 | } 182 | ], 183 | "measurement": "disk", 184 | "policy": "default", 185 | "refId": "B", 186 | "resultFormat": "time_series", 187 | "select": [ 188 | [ 189 | { 190 | "params": [ 191 | "free" 192 | ], 193 | "type": "field" 194 | }, 195 | { 196 | "params": [], 197 | "type": "mean" 198 | } 199 | ] 200 | ], 201 | "tags": [ 202 | { 203 | "key": "host", 204 | "operator": "=~", 205 | "value": "/^$host$/" 206 | } 207 | ] 208 | }, 209 | { 210 | "alias": "inodes: total, $tag_path", 211 | "dsType": "influxdb", 212 | "groupBy": [ 213 | { 214 | "params": [ 215 | "$interval" 216 | ], 217 | "type": "time" 218 | }, 219 | { 220 | "params": [ 221 | "path" 222 | ], 223 | "type": "tag" 224 | }, 225 | { 226 | "params": [ 227 | "null" 228 | ], 229 | "type": "fill" 230 | } 231 | ], 232 | "measurement": "disk", 233 | "policy": "default", 234 | "refId": "C", 235 | "resultFormat": "time_series", 236 | "select": [ 237 | [ 238 | { 239 | "params": [ 240 | "inodes_total" 241 | ], 242 | "type": "field" 243 | }, 244 | { 245 | "params": [], 246 | "type": "mean" 247 | } 248 | ] 249 | ], 250 | "tags": [ 251 | { 252 | "key": "host", 253 | "operator": "=~", 254 | "value": "/^$host$/" 255 | } 256 | ] 257 | }, 258 | { 259 | "alias": "inodes: free, $tag_path", 260 | "dsType": "influxdb", 261 | "groupBy": [ 262 | { 263 | "params": [ 264 | "$interval" 265 | ], 266 | "type": "time" 267 | }, 268 | { 269 | "params": [ 270 | "path" 271 | ], 272 | "type": "tag" 273 | }, 274 | { 275 | "params": [ 276 | "null" 277 | ], 278 | "type": "fill" 279 | } 280 | ], 281 | "measurement": "disk", 282 | "policy": "default", 283 | "refId": "D", 284 | "resultFormat": "time_series", 285 | "select": [ 286 | [ 287 | { 288 | "params": [ 289 | "inodes_free" 290 | ], 291 | "type": "field" 292 | }, 293 | { 294 | "params": [], 295 | "type": "mean" 296 | } 297 | ] 298 | ], 299 | "tags": [ 300 | { 301 | "key": "host", 302 | "operator": "=~", 303 | "value": "/^$host$/" 304 | } 305 | ] 306 | } 307 | ], 308 | "thresholds": [], 309 | "timeFrom": null, 310 | "timeShift": null, 311 | "title": "DISK partitions", 312 | "tooltip": { 313 | "msResolution": false, 314 | "shared": true, 315 | "sort": 0, 316 | "value_type": "individual" 317 | }, 318 | "type": "graph", 319 | "xaxis": { 320 | "mode": "time", 321 | "name": null, 322 | "show": true, 323 | "values": [] 324 | }, 325 | "yaxes": [ 326 | { 327 | "format": "bytes", 328 | "label": "space", 329 | "logBase": 1, 330 | "max": null, 331 | "min": "0", 332 | "show": true 333 | }, 334 | { 335 | "format": "short", 336 | "label": "inodes", 337 | "logBase": 1, 338 | "max": null, 339 | "min": "0", 340 | "show": true 341 | } 342 | ] 343 | }, 344 | { 345 | "alert": { 346 | "conditions": [ 347 | { 348 | "evaluator": { 349 | "params": [ 350 | 10000 351 | ], 352 | "type": "gt" 353 | }, 354 | "operator": { 355 | "type": "and" 356 | }, 357 | "query": { 358 | "datasourceId": 2, 359 | "model": { 360 | "alias": "blocked (Alerting)", 361 | "dsType": "influxdb", 362 | "groupBy": [ 363 | { 364 | "params": [ 365 | "$interval" 366 | ], 367 | "type": "time" 368 | }, 369 | { 370 | "params": [ 371 | "host" 372 | ], 373 | "type": "tag" 374 | }, 375 | { 376 | "params": [ 377 | "null" 378 | ], 379 | "type": "fill" 380 | } 381 | ], 382 | "hide": true, 383 | "measurement": "processes", 384 | "policy": "default", 385 | "refId": "E", 386 | "resultFormat": "time_series", 387 | "select": [ 388 | [ 389 | { 390 | "params": [ 391 | "blocked" 392 | ], 393 | "type": "field" 394 | }, 395 | { 396 | "params": [], 397 | "type": "max" 398 | } 399 | ] 400 | ], 401 | "tags": [] 402 | }, 403 | "params": [ 404 | "E", 405 | "1h", 406 | "now" 407 | ] 408 | }, 409 | "reducer": { 410 | "params": [], 411 | "type": "max" 412 | }, 413 | "type": "query" 414 | } 415 | ], 416 | "executionErrorState": "keep_state", 417 | "frequency": "1h", 418 | "handler": 1, 419 | "name": "too many blocked processes (SPAM-Aktivität ?)", 420 | "noDataState": "no_data", 421 | "notifications": [] 422 | }, 423 | "aliasColors": {}, 424 | "bars": false, 425 | "datasource": "${DS_SERVERMONITOR}", 426 | "decimals": 0, 427 | "editable": true, 428 | "error": false, 429 | "fill": 0, 430 | "id": 11, 431 | "legend": { 432 | "avg": false, 433 | "current": false, 434 | "max": false, 435 | "min": false, 436 | "show": true, 437 | "total": false, 438 | "values": false 439 | }, 440 | "lines": true, 441 | "linewidth": 2, 442 | "links": [], 443 | "nullPointMode": "connected", 444 | "percentage": false, 445 | "pointradius": 3, 446 | "points": false, 447 | "renderer": "flot", 448 | "seriesOverrides": [ 449 | { 450 | "alias": "running", 451 | "zindex": 3 452 | } 453 | ], 454 | "span": 4, 455 | "stack": false, 456 | "steppedLine": false, 457 | "targets": [ 458 | { 459 | "alias": "Total", 460 | "dsType": "influxdb", 461 | "groupBy": [ 462 | { 463 | "params": [ 464 | "$interval" 465 | ], 466 | "type": "time" 467 | }, 468 | { 469 | "params": [ 470 | "null" 471 | ], 472 | "type": "fill" 473 | } 474 | ], 475 | "measurement": "processes", 476 | "policy": "default", 477 | "refId": "A", 478 | "resultFormat": "time_series", 479 | "select": [ 480 | [ 481 | { 482 | "params": [ 483 | "total" 484 | ], 485 | "type": "field" 486 | }, 487 | { 488 | "params": [], 489 | "type": "mean" 490 | } 491 | ] 492 | ], 493 | "tags": [ 494 | { 495 | "key": "host", 496 | "operator": "=~", 497 | "value": "/^$host$/" 498 | } 499 | ] 500 | }, 501 | { 502 | "alias": "running", 503 | "dsType": "influxdb", 504 | "groupBy": [ 505 | { 506 | "params": [ 507 | "$interval" 508 | ], 509 | "type": "time" 510 | }, 511 | { 512 | "params": [ 513 | "null" 514 | ], 515 | "type": "fill" 516 | } 517 | ], 518 | "measurement": "processes", 519 | "policy": "default", 520 | "refId": "B", 521 | "resultFormat": "time_series", 522 | "select": [ 523 | [ 524 | { 525 | "params": [ 526 | "running" 527 | ], 528 | "type": "field" 529 | }, 530 | { 531 | "params": [], 532 | "type": "mean" 533 | } 534 | ] 535 | ], 536 | "tags": [ 537 | { 538 | "key": "host", 539 | "operator": "=~", 540 | "value": "/^$host$/" 541 | } 542 | ] 543 | }, 544 | { 545 | "alias": "blocked", 546 | "dsType": "influxdb", 547 | "groupBy": [ 548 | { 549 | "params": [ 550 | "$interval" 551 | ], 552 | "type": "time" 553 | }, 554 | { 555 | "params": [ 556 | "null" 557 | ], 558 | "type": "fill" 559 | } 560 | ], 561 | "measurement": "processes", 562 | "policy": "default", 563 | "refId": "C", 564 | "resultFormat": "time_series", 565 | "select": [ 566 | [ 567 | { 568 | "params": [ 569 | "blocked" 570 | ], 571 | "type": "field" 572 | }, 573 | { 574 | "params": [], 575 | "type": "mean" 576 | } 577 | ] 578 | ], 579 | "tags": [ 580 | { 581 | "key": "host", 582 | "operator": "=~", 583 | "value": "/^$host$/" 584 | } 585 | ] 586 | }, 587 | { 588 | "alias": "stopped", 589 | "dsType": "influxdb", 590 | "groupBy": [ 591 | { 592 | "params": [ 593 | "$interval" 594 | ], 595 | "type": "time" 596 | }, 597 | { 598 | "params": [ 599 | "null" 600 | ], 601 | "type": "fill" 602 | } 603 | ], 604 | "measurement": "processes", 605 | "policy": "default", 606 | "refId": "D", 607 | "resultFormat": "time_series", 608 | "select": [ 609 | [ 610 | { 611 | "params": [ 612 | "stopped" 613 | ], 614 | "type": "field" 615 | }, 616 | { 617 | "params": [], 618 | "type": "mean" 619 | } 620 | ] 621 | ], 622 | "tags": [ 623 | { 624 | "key": "host", 625 | "operator": "=~", 626 | "value": "/^$host$/" 627 | } 628 | ] 629 | }, 630 | { 631 | "alias": "blocked (Alerting)", 632 | "dsType": "influxdb", 633 | "groupBy": [ 634 | { 635 | "params": [ 636 | "$interval" 637 | ], 638 | "type": "time" 639 | }, 640 | { 641 | "params": [ 642 | "host" 643 | ], 644 | "type": "tag" 645 | }, 646 | { 647 | "params": [ 648 | "null" 649 | ], 650 | "type": "fill" 651 | } 652 | ], 653 | "hide": true, 654 | "measurement": "processes", 655 | "policy": "default", 656 | "refId": "E", 657 | "resultFormat": "time_series", 658 | "select": [ 659 | [ 660 | { 661 | "params": [ 662 | "blocked" 663 | ], 664 | "type": "field" 665 | }, 666 | { 667 | "params": [], 668 | "type": "max" 669 | } 670 | ] 671 | ], 672 | "tags": [] 673 | } 674 | ], 675 | "thresholds": [ 676 | { 677 | "colorMode": "critical", 678 | "fill": true, 679 | "line": true, 680 | "op": "gt", 681 | "value": 10000 682 | } 683 | ], 684 | "timeFrom": null, 685 | "timeShift": null, 686 | "title": "Processes", 687 | "tooltip": { 688 | "msResolution": false, 689 | "shared": true, 690 | "sort": 0, 691 | "value_type": "individual" 692 | }, 693 | "type": "graph", 694 | "xaxis": { 695 | "mode": "time", 696 | "name": null, 697 | "show": true, 698 | "values": [] 699 | }, 700 | "yaxes": [ 701 | { 702 | "format": "short", 703 | "label": null, 704 | "logBase": 1, 705 | "max": null, 706 | "min": null, 707 | "show": true 708 | }, 709 | { 710 | "format": "short", 711 | "label": null, 712 | "logBase": 1, 713 | "max": null, 714 | "min": null, 715 | "show": false 716 | } 717 | ] 718 | }, 719 | { 720 | "aliasColors": {}, 721 | "bars": false, 722 | "datasource": "${DS_SERVERMONITOR}", 723 | "editable": true, 724 | "error": false, 725 | "fill": 0, 726 | "id": 5, 727 | "interval": ">5m", 728 | "legend": { 729 | "alignAsTable": false, 730 | "avg": false, 731 | "current": false, 732 | "hideEmpty": true, 733 | "hideZero": true, 734 | "max": false, 735 | "min": false, 736 | "rightSide": false, 737 | "show": true, 738 | "total": false, 739 | "values": false 740 | }, 741 | "lines": true, 742 | "linewidth": 2, 743 | "links": [], 744 | "nullPointMode": "connected", 745 | "percentage": false, 746 | "pointradius": 5, 747 | "points": false, 748 | "renderer": "flot", 749 | "seriesOverrides": [ 750 | { 751 | "alias": "used", 752 | "fill": 4, 753 | "linewidth": 0, 754 | "yaxis": 2 755 | } 756 | ], 757 | "span": 4, 758 | "stack": false, 759 | "steppedLine": false, 760 | "targets": [ 761 | { 762 | "alias": "in", 763 | "dsType": "influxdb", 764 | "groupBy": [ 765 | { 766 | "params": [ 767 | "$interval" 768 | ], 769 | "type": "time" 770 | }, 771 | { 772 | "params": [ 773 | "host" 774 | ], 775 | "type": "tag" 776 | }, 777 | { 778 | "params": [ 779 | "null" 780 | ], 781 | "type": "fill" 782 | } 783 | ], 784 | "measurement": "swap", 785 | "policy": "default", 786 | "refId": "B", 787 | "resultFormat": "time_series", 788 | "select": [ 789 | [ 790 | { 791 | "params": [ 792 | "in" 793 | ], 794 | "type": "field" 795 | }, 796 | { 797 | "params": [], 798 | "type": "mean" 799 | }, 800 | { 801 | "params": [ 802 | "1s" 803 | ], 804 | "type": "derivative" 805 | } 806 | ] 807 | ], 808 | "tags": [ 809 | { 810 | "key": "host", 811 | "operator": "=~", 812 | "value": "/^$host$/" 813 | } 814 | ] 815 | }, 816 | { 817 | "alias": "out", 818 | "dsType": "influxdb", 819 | "groupBy": [ 820 | { 821 | "params": [ 822 | "$interval" 823 | ], 824 | "type": "time" 825 | }, 826 | { 827 | "params": [ 828 | "host" 829 | ], 830 | "type": "tag" 831 | }, 832 | { 833 | "params": [ 834 | "null" 835 | ], 836 | "type": "fill" 837 | } 838 | ], 839 | "measurement": "swap", 840 | "policy": "default", 841 | "refId": "A", 842 | "resultFormat": "time_series", 843 | "select": [ 844 | [ 845 | { 846 | "params": [ 847 | "out" 848 | ], 849 | "type": "field" 850 | }, 851 | { 852 | "params": [], 853 | "type": "mean" 854 | }, 855 | { 856 | "params": [ 857 | "1s" 858 | ], 859 | "type": "derivative" 860 | } 861 | ] 862 | ], 863 | "tags": [ 864 | { 865 | "key": "host", 866 | "operator": "=~", 867 | "value": "/^$host$/" 868 | } 869 | ] 870 | }, 871 | { 872 | "alias": "used", 873 | "dsType": "influxdb", 874 | "groupBy": [ 875 | { 876 | "params": [ 877 | "$interval" 878 | ], 879 | "type": "time" 880 | }, 881 | { 882 | "params": [ 883 | "host" 884 | ], 885 | "type": "tag" 886 | }, 887 | { 888 | "params": [ 889 | "null" 890 | ], 891 | "type": "fill" 892 | } 893 | ], 894 | "measurement": "swap", 895 | "policy": "default", 896 | "refId": "C", 897 | "resultFormat": "time_series", 898 | "select": [ 899 | [ 900 | { 901 | "params": [ 902 | "used_percent" 903 | ], 904 | "type": "field" 905 | }, 906 | { 907 | "params": [], 908 | "type": "mean" 909 | } 910 | ] 911 | ], 912 | "tags": [ 913 | { 914 | "key": "host", 915 | "operator": "=~", 916 | "value": "/^$host$/" 917 | } 918 | ] 919 | } 920 | ], 921 | "thresholds": [ 922 | { 923 | "colorMode": "critical", 924 | "fill": true, 925 | "line": true, 926 | "op": "gt" 927 | } 928 | ], 929 | "timeFrom": null, 930 | "timeShift": null, 931 | "title": "swap", 932 | "tooltip": { 933 | "msResolution": false, 934 | "shared": true, 935 | "sort": 0, 936 | "value_type": "individual" 937 | }, 938 | "type": "graph", 939 | "xaxis": { 940 | "mode": "time", 941 | "name": null, 942 | "show": true, 943 | "values": [] 944 | }, 945 | "yaxes": [ 946 | { 947 | "format": "Bps", 948 | "label": "I/O", 949 | "logBase": 1, 950 | "max": null, 951 | "min": "0", 952 | "show": true 953 | }, 954 | { 955 | "format": "percent", 956 | "label": "used", 957 | "logBase": 1, 958 | "max": "100", 959 | "min": "0", 960 | "show": true 961 | } 962 | ] 963 | } 964 | ], 965 | "repeat": null, 966 | "repeatIteration": null, 967 | "repeatRowId": null, 968 | "showTitle": false, 969 | "title": "Dashboard Row", 970 | "titleSize": "h6" 971 | }, 972 | { 973 | "collapse": false, 974 | "height": 245, 975 | "panels": [ 976 | { 977 | "aliasColors": {}, 978 | "bars": false, 979 | "datasource": "${DS_SERVERMONITOR}", 980 | "editable": true, 981 | "error": false, 982 | "fill": 0, 983 | "hideTimeOverride": false, 984 | "id": 1, 985 | "interval": ">2s", 986 | "legend": { 987 | "alignAsTable": true, 988 | "avg": false, 989 | "current": false, 990 | "max": true, 991 | "min": true, 992 | "rightSide": true, 993 | "show": true, 994 | "total": false, 995 | "values": true 996 | }, 997 | "lines": true, 998 | "linewidth": 1, 999 | "links": [], 1000 | "nullPointMode": "connected", 1001 | "percentage": false, 1002 | "pointradius": 5, 1003 | "points": false, 1004 | "renderer": "flot", 1005 | "seriesOverrides": [ 1006 | { 1007 | "alias": "/cores/", 1008 | "linewidth": 2, 1009 | "stack": false, 1010 | "yaxis": 2, 1011 | "zindex": -2 1012 | }, 1013 | { 1014 | "alias": "IDLE", 1015 | "color": "#629E51", 1016 | "stack": false 1017 | }, 1018 | { 1019 | "alias": "usage_iowait", 1020 | "color": "#890F02", 1021 | "fill": 6, 1022 | "fillBelowTo": "usage_user" 1023 | }, 1024 | { 1025 | "alias": "usage_user", 1026 | "fillBelowTo": "usage_system" 1027 | }, 1028 | { 1029 | "alias": "usage_system", 1030 | "fill": 5 1031 | } 1032 | ], 1033 | "span": 8, 1034 | "stack": true, 1035 | "steppedLine": false, 1036 | "targets": [ 1037 | { 1038 | "alias": "# cores", 1039 | "dsType": "influxdb", 1040 | "groupBy": [ 1041 | { 1042 | "params": [ 1043 | "$interval" 1044 | ], 1045 | "type": "time" 1046 | }, 1047 | { 1048 | "params": [ 1049 | "host" 1050 | ], 1051 | "type": "tag" 1052 | }, 1053 | { 1054 | "params": [ 1055 | "none" 1056 | ], 1057 | "type": "fill" 1058 | } 1059 | ], 1060 | "hide": true, 1061 | "measurement": "system", 1062 | "policy": "default", 1063 | "query": "SELECT derivative(mean(\"time_iowait\"), 2s) FROM \"cpu\" WHERE $timeFilter GROUP BY time($interval) fill(none)", 1064 | "rawQuery": false, 1065 | "refId": "B", 1066 | "resultFormat": "time_series", 1067 | "select": [ 1068 | [ 1069 | { 1070 | "params": [ 1071 | "n_cpus" 1072 | ], 1073 | "type": "field" 1074 | }, 1075 | { 1076 | "params": [], 1077 | "type": "mean" 1078 | } 1079 | ] 1080 | ], 1081 | "tags": [ 1082 | { 1083 | "key": "host", 1084 | "operator": "=~", 1085 | "value": "/^$host$/" 1086 | } 1087 | ] 1088 | }, 1089 | { 1090 | "alias": "usage_system", 1091 | "dsType": "influxdb", 1092 | "groupBy": [ 1093 | { 1094 | "params": [ 1095 | "$interval" 1096 | ], 1097 | "type": "time" 1098 | }, 1099 | { 1100 | "params": [ 1101 | "host" 1102 | ], 1103 | "type": "tag" 1104 | }, 1105 | { 1106 | "params": [ 1107 | "none" 1108 | ], 1109 | "type": "fill" 1110 | } 1111 | ], 1112 | "hide": false, 1113 | "measurement": "cpu", 1114 | "policy": "default", 1115 | "query": "SELECT derivative(mean(\"time_iowait\"), 2s) FROM \"cpu\" WHERE $timeFilter GROUP BY time($interval) ,\"host\" fill(none)", 1116 | "rawQuery": false, 1117 | "refId": "C", 1118 | "resultFormat": "time_series", 1119 | "select": [ 1120 | [ 1121 | { 1122 | "params": [ 1123 | "usage_system" 1124 | ], 1125 | "type": "field" 1126 | }, 1127 | { 1128 | "params": [], 1129 | "type": "mean" 1130 | } 1131 | ] 1132 | ], 1133 | "tags": [ 1134 | { 1135 | "key": "host", 1136 | "operator": "=~", 1137 | "value": "/^$host$/" 1138 | } 1139 | ] 1140 | }, 1141 | { 1142 | "alias": "usage_user", 1143 | "dsType": "influxdb", 1144 | "groupBy": [ 1145 | { 1146 | "params": [ 1147 | "$interval" 1148 | ], 1149 | "type": "time" 1150 | }, 1151 | { 1152 | "params": [ 1153 | "host" 1154 | ], 1155 | "type": "tag" 1156 | }, 1157 | { 1158 | "params": [ 1159 | "none" 1160 | ], 1161 | "type": "fill" 1162 | } 1163 | ], 1164 | "hide": false, 1165 | "measurement": "cpu", 1166 | "policy": "default", 1167 | "query": "SELECT derivative(mean(\"time_iowait\"), 2s) FROM \"cpu\" WHERE $timeFilter GROUP BY time($interval) ,\"host\" fill(none)", 1168 | "rawQuery": false, 1169 | "refId": "D", 1170 | "resultFormat": "time_series", 1171 | "select": [ 1172 | [ 1173 | { 1174 | "params": [ 1175 | "usage_user" 1176 | ], 1177 | "type": "field" 1178 | }, 1179 | { 1180 | "params": [], 1181 | "type": "mean" 1182 | } 1183 | ] 1184 | ], 1185 | "tags": [ 1186 | { 1187 | "key": "host", 1188 | "operator": "=~", 1189 | "value": "/^$host$/" 1190 | } 1191 | ] 1192 | }, 1193 | { 1194 | "alias": "usage_iowait", 1195 | "dsType": "influxdb", 1196 | "groupBy": [ 1197 | { 1198 | "params": [ 1199 | "$interval" 1200 | ], 1201 | "type": "time" 1202 | }, 1203 | { 1204 | "params": [ 1205 | "host" 1206 | ], 1207 | "type": "tag" 1208 | }, 1209 | { 1210 | "params": [ 1211 | "none" 1212 | ], 1213 | "type": "fill" 1214 | } 1215 | ], 1216 | "hide": false, 1217 | "measurement": "cpu", 1218 | "policy": "default", 1219 | "query": "SELECT derivative(mean(\"time_iowait\"), 2s) FROM \"cpu\" WHERE $timeFilter GROUP BY time($interval) ,\"host\" fill(none)", 1220 | "rawQuery": false, 1221 | "refId": "A", 1222 | "resultFormat": "time_series", 1223 | "select": [ 1224 | [ 1225 | { 1226 | "params": [ 1227 | "usage_iowait" 1228 | ], 1229 | "type": "field" 1230 | }, 1231 | { 1232 | "params": [], 1233 | "type": "mean" 1234 | } 1235 | ] 1236 | ], 1237 | "tags": [ 1238 | { 1239 | "key": "host", 1240 | "operator": "=~", 1241 | "value": "/^$host$/" 1242 | } 1243 | ] 1244 | }, 1245 | { 1246 | "alias": "IDLE", 1247 | "dsType": "influxdb", 1248 | "groupBy": [ 1249 | { 1250 | "params": [ 1251 | "$interval" 1252 | ], 1253 | "type": "time" 1254 | }, 1255 | { 1256 | "params": [ 1257 | "host" 1258 | ], 1259 | "type": "tag" 1260 | }, 1261 | { 1262 | "params": [ 1263 | "none" 1264 | ], 1265 | "type": "fill" 1266 | } 1267 | ], 1268 | "hide": true, 1269 | "measurement": "cpu", 1270 | "policy": "default", 1271 | "query": "SELECT derivative(mean(\"time_iowait\"), 2s) FROM \"cpu\" WHERE $timeFilter GROUP BY time($interval) ,\"host\" fill(none)", 1272 | "rawQuery": false, 1273 | "refId": "E", 1274 | "resultFormat": "time_series", 1275 | "select": [ 1276 | [ 1277 | { 1278 | "params": [ 1279 | "usage_idle" 1280 | ], 1281 | "type": "field" 1282 | }, 1283 | { 1284 | "params": [], 1285 | "type": "mean" 1286 | } 1287 | ] 1288 | ], 1289 | "tags": [ 1290 | { 1291 | "key": "host", 1292 | "operator": "=~", 1293 | "value": "/^$host$/" 1294 | } 1295 | ] 1296 | } 1297 | ], 1298 | "thresholds": [], 1299 | "timeFrom": null, 1300 | "timeShift": null, 1301 | "title": "CPU usage", 1302 | "tooltip": { 1303 | "msResolution": false, 1304 | "shared": true, 1305 | "sort": 0, 1306 | "value_type": "individual" 1307 | }, 1308 | "type": "graph", 1309 | "xaxis": { 1310 | "mode": "time", 1311 | "name": null, 1312 | "show": true, 1313 | "values": [] 1314 | }, 1315 | "yaxes": [ 1316 | { 1317 | "format": "percent", 1318 | "label": "usage", 1319 | "logBase": 1, 1320 | "max": "100", 1321 | "min": "0", 1322 | "show": true 1323 | }, 1324 | { 1325 | "format": "short", 1326 | "label": "", 1327 | "logBase": 1, 1328 | "max": "10", 1329 | "min": "0", 1330 | "show": true 1331 | } 1332 | ] 1333 | }, 1334 | { 1335 | "aliasColors": {}, 1336 | "bars": false, 1337 | "datasource": "${DS_SERVERMONITOR}", 1338 | "editable": true, 1339 | "error": false, 1340 | "fill": 0, 1341 | "id": 9, 1342 | "legend": { 1343 | "avg": false, 1344 | "current": false, 1345 | "max": false, 1346 | "min": false, 1347 | "show": true, 1348 | "total": false, 1349 | "values": false 1350 | }, 1351 | "lines": true, 1352 | "linewidth": 2, 1353 | "links": [], 1354 | "nullPointMode": "connected", 1355 | "percentage": false, 1356 | "pointradius": 3, 1357 | "points": false, 1358 | "renderer": "flot", 1359 | "seriesOverrides": [ 1360 | { 1361 | "alias": "Total", 1362 | "fillBelowTo": "Available", 1363 | "lines": false 1364 | }, 1365 | { 1366 | "alias": "Available", 1367 | "color": "#7EB26D", 1368 | "fill": 2 1369 | } 1370 | ], 1371 | "span": 4, 1372 | "stack": false, 1373 | "steppedLine": false, 1374 | "targets": [ 1375 | { 1376 | "alias": "Available", 1377 | "dsType": "influxdb", 1378 | "groupBy": [ 1379 | { 1380 | "params": [ 1381 | "$interval" 1382 | ], 1383 | "type": "time" 1384 | }, 1385 | { 1386 | "params": [ 1387 | "host" 1388 | ], 1389 | "type": "tag" 1390 | }, 1391 | { 1392 | "params": [ 1393 | "null" 1394 | ], 1395 | "type": "fill" 1396 | } 1397 | ], 1398 | "measurement": "mem", 1399 | "policy": "default", 1400 | "refId": "A", 1401 | "resultFormat": "time_series", 1402 | "select": [ 1403 | [ 1404 | { 1405 | "params": [ 1406 | "available" 1407 | ], 1408 | "type": "field" 1409 | }, 1410 | { 1411 | "params": [], 1412 | "type": "mean" 1413 | } 1414 | ] 1415 | ], 1416 | "tags": [ 1417 | { 1418 | "key": "host", 1419 | "operator": "=~", 1420 | "value": "/^$host$/" 1421 | } 1422 | ] 1423 | }, 1424 | { 1425 | "alias": "Total", 1426 | "dsType": "influxdb", 1427 | "groupBy": [ 1428 | { 1429 | "params": [ 1430 | "$interval" 1431 | ], 1432 | "type": "time" 1433 | }, 1434 | { 1435 | "params": [ 1436 | "host" 1437 | ], 1438 | "type": "tag" 1439 | }, 1440 | { 1441 | "params": [ 1442 | "null" 1443 | ], 1444 | "type": "fill" 1445 | } 1446 | ], 1447 | "measurement": "mem", 1448 | "policy": "default", 1449 | "refId": "B", 1450 | "resultFormat": "time_series", 1451 | "select": [ 1452 | [ 1453 | { 1454 | "params": [ 1455 | "total" 1456 | ], 1457 | "type": "field" 1458 | }, 1459 | { 1460 | "params": [], 1461 | "type": "mean" 1462 | } 1463 | ] 1464 | ], 1465 | "tags": [ 1466 | { 1467 | "key": "host", 1468 | "operator": "=~", 1469 | "value": "/^$host$/" 1470 | } 1471 | ] 1472 | } 1473 | ], 1474 | "thresholds": [], 1475 | "timeFrom": null, 1476 | "timeShift": null, 1477 | "title": "RAM", 1478 | "tooltip": { 1479 | "msResolution": false, 1480 | "shared": true, 1481 | "sort": 0, 1482 | "value_type": "individual" 1483 | }, 1484 | "type": "graph", 1485 | "xaxis": { 1486 | "mode": "time", 1487 | "name": null, 1488 | "show": true, 1489 | "values": [] 1490 | }, 1491 | "yaxes": [ 1492 | { 1493 | "format": "bytes", 1494 | "label": null, 1495 | "logBase": 1, 1496 | "max": null, 1497 | "min": "0", 1498 | "show": true 1499 | }, 1500 | { 1501 | "format": "short", 1502 | "label": null, 1503 | "logBase": 1, 1504 | "max": null, 1505 | "min": null, 1506 | "show": true 1507 | } 1508 | ] 1509 | } 1510 | ], 1511 | "repeat": null, 1512 | "repeatIteration": null, 1513 | "repeatRowId": null, 1514 | "showTitle": false, 1515 | "title": "Dashboard Row", 1516 | "titleSize": "h6" 1517 | }, 1518 | { 1519 | "collapse": false, 1520 | "height": 224, 1521 | "panels": [ 1522 | { 1523 | "aliasColors": {}, 1524 | "bars": false, 1525 | "datasource": "${DS_SERVERMONITOR}", 1526 | "editable": true, 1527 | "error": false, 1528 | "fill": 0, 1529 | "id": 12, 1530 | "interval": ">1s", 1531 | "legend": { 1532 | "alignAsTable": true, 1533 | "avg": true, 1534 | "current": false, 1535 | "max": true, 1536 | "min": false, 1537 | "rightSide": true, 1538 | "show": true, 1539 | "total": false, 1540 | "values": true 1541 | }, 1542 | "lines": false, 1543 | "linewidth": 0, 1544 | "links": [], 1545 | "nullPointMode": "connected", 1546 | "percentage": false, 1547 | "pointradius": 1, 1548 | "points": true, 1549 | "renderer": "flot", 1550 | "seriesOverrides": [ 1551 | { 1552 | "alias": "/[ms]/", 1553 | "fill": 1, 1554 | "lines": true, 1555 | "linewidth": 2, 1556 | "points": false 1557 | }, 1558 | { 1559 | "alias": "/In/i", 1560 | "color": "#1F78C1" 1561 | }, 1562 | { 1563 | "alias": "/Out/i", 1564 | "color": "#CCA300" 1565 | } 1566 | ], 1567 | "span": 8, 1568 | "stack": false, 1569 | "steppedLine": false, 1570 | "targets": [ 1571 | { 1572 | "alias": "Out", 1573 | "dsType": "influxdb", 1574 | "groupBy": [ 1575 | { 1576 | "params": [ 1577 | "1s" 1578 | ], 1579 | "type": "time" 1580 | }, 1581 | { 1582 | "params": [ 1583 | "host" 1584 | ], 1585 | "type": "tag" 1586 | }, 1587 | { 1588 | "params": [ 1589 | "null" 1590 | ], 1591 | "type": "fill" 1592 | } 1593 | ], 1594 | "hide": true, 1595 | "measurement": "nstat", 1596 | "policy": "default", 1597 | "query": "SELECT derivative(mean(\"IpExtOutOctets\"), 1s) FROM \"nstat\" WHERE \"host\" =~ /^$host$/ AND $timeFilter GROUP BY time(1m), \"host\" fill(null)", 1598 | "rawQuery": false, 1599 | "refId": "B", 1600 | "resultFormat": "time_series", 1601 | "select": [ 1602 | [ 1603 | { 1604 | "params": [ 1605 | "IpExtOutOctets" 1606 | ], 1607 | "type": "field" 1608 | }, 1609 | { 1610 | "params": [], 1611 | "type": "mean" 1612 | }, 1613 | { 1614 | "params": [ 1615 | "1s" 1616 | ], 1617 | "type": "derivative" 1618 | } 1619 | ] 1620 | ], 1621 | "tags": [ 1622 | { 1623 | "key": "host", 1624 | "operator": "=~", 1625 | "value": "/^$host$/" 1626 | } 1627 | ] 1628 | }, 1629 | { 1630 | "alias": "Out (5m)", 1631 | "dsType": "influxdb", 1632 | "groupBy": [ 1633 | { 1634 | "params": [ 1635 | "5m" 1636 | ], 1637 | "type": "time" 1638 | }, 1639 | { 1640 | "params": [ 1641 | "host" 1642 | ], 1643 | "type": "tag" 1644 | }, 1645 | { 1646 | "params": [ 1647 | "null" 1648 | ], 1649 | "type": "fill" 1650 | } 1651 | ], 1652 | "measurement": "nstat", 1653 | "policy": "default", 1654 | "refId": "C", 1655 | "resultFormat": "time_series", 1656 | "select": [ 1657 | [ 1658 | { 1659 | "params": [ 1660 | "IpExtOutOctets" 1661 | ], 1662 | "type": "field" 1663 | }, 1664 | { 1665 | "params": [], 1666 | "type": "mean" 1667 | }, 1668 | { 1669 | "params": [ 1670 | "1s" 1671 | ], 1672 | "type": "derivative" 1673 | } 1674 | ] 1675 | ], 1676 | "tags": [ 1677 | { 1678 | "key": "host", 1679 | "operator": "=~", 1680 | "value": "/^$host$/" 1681 | } 1682 | ] 1683 | }, 1684 | { 1685 | "alias": "In", 1686 | "dsType": "influxdb", 1687 | "groupBy": [ 1688 | { 1689 | "params": [ 1690 | "10s" 1691 | ], 1692 | "type": "time" 1693 | }, 1694 | { 1695 | "params": [ 1696 | "host" 1697 | ], 1698 | "type": "tag" 1699 | }, 1700 | { 1701 | "params": [ 1702 | "null" 1703 | ], 1704 | "type": "fill" 1705 | } 1706 | ], 1707 | "hide": true, 1708 | "measurement": "nstat", 1709 | "policy": "default", 1710 | "refId": "A", 1711 | "resultFormat": "time_series", 1712 | "select": [ 1713 | [ 1714 | { 1715 | "params": [ 1716 | "IpExtInOctets" 1717 | ], 1718 | "type": "field" 1719 | }, 1720 | { 1721 | "params": [], 1722 | "type": "mean" 1723 | }, 1724 | { 1725 | "params": [ 1726 | "1s" 1727 | ], 1728 | "type": "derivative" 1729 | } 1730 | ] 1731 | ], 1732 | "tags": [ 1733 | { 1734 | "key": "host", 1735 | "operator": "=~", 1736 | "value": "/^$host$/" 1737 | } 1738 | ] 1739 | }, 1740 | { 1741 | "alias": "In (5m)", 1742 | "dsType": "influxdb", 1743 | "groupBy": [ 1744 | { 1745 | "params": [ 1746 | "5m" 1747 | ], 1748 | "type": "time" 1749 | }, 1750 | { 1751 | "params": [ 1752 | "host" 1753 | ], 1754 | "type": "tag" 1755 | }, 1756 | { 1757 | "params": [ 1758 | "null" 1759 | ], 1760 | "type": "fill" 1761 | } 1762 | ], 1763 | "hide": false, 1764 | "measurement": "nstat", 1765 | "policy": "default", 1766 | "refId": "D", 1767 | "resultFormat": "time_series", 1768 | "select": [ 1769 | [ 1770 | { 1771 | "params": [ 1772 | "IpExtInOctets" 1773 | ], 1774 | "type": "field" 1775 | }, 1776 | { 1777 | "params": [], 1778 | "type": "mean" 1779 | }, 1780 | { 1781 | "params": [ 1782 | "1s" 1783 | ], 1784 | "type": "derivative" 1785 | }, 1786 | { 1787 | "params": [ 1788 | "*(-1)" 1789 | ], 1790 | "type": "math" 1791 | } 1792 | ] 1793 | ], 1794 | "tags": [ 1795 | { 1796 | "key": "host", 1797 | "operator": "=~", 1798 | "value": "/^$host$/" 1799 | } 1800 | ] 1801 | } 1802 | ], 1803 | "thresholds": [], 1804 | "timeFrom": null, 1805 | "timeShift": null, 1806 | "title": "IP traffic", 1807 | "tooltip": { 1808 | "msResolution": false, 1809 | "shared": true, 1810 | "sort": 0, 1811 | "value_type": "individual" 1812 | }, 1813 | "type": "graph", 1814 | "xaxis": { 1815 | "mode": "time", 1816 | "name": null, 1817 | "show": true, 1818 | "values": [] 1819 | }, 1820 | "yaxes": [ 1821 | { 1822 | "format": "Bps", 1823 | "label": "", 1824 | "logBase": 1, 1825 | "max": null, 1826 | "min": null, 1827 | "show": true 1828 | }, 1829 | { 1830 | "format": "short", 1831 | "label": null, 1832 | "logBase": 1, 1833 | "max": null, 1834 | "min": null, 1835 | "show": true 1836 | } 1837 | ] 1838 | }, 1839 | { 1840 | "aliasColors": {}, 1841 | "bars": false, 1842 | "datasource": "${DS_SERVERMONITOR}", 1843 | "editable": true, 1844 | "error": false, 1845 | "fill": 3, 1846 | "id": 6, 1847 | "legend": { 1848 | "alignAsTable": false, 1849 | "avg": false, 1850 | "current": false, 1851 | "max": true, 1852 | "min": false, 1853 | "rightSide": false, 1854 | "show": true, 1855 | "total": false, 1856 | "values": true 1857 | }, 1858 | "lines": true, 1859 | "linewidth": 1, 1860 | "links": [], 1861 | "nullPointMode": "connected", 1862 | "percentage": false, 1863 | "pointradius": 5, 1864 | "points": false, 1865 | "renderer": "flot", 1866 | "seriesOverrides": [ 1867 | { 1868 | "alias": "/.*cores$/", 1869 | "fill": 0 1870 | } 1871 | ], 1872 | "span": 4, 1873 | "stack": false, 1874 | "steppedLine": false, 1875 | "targets": [ 1876 | { 1877 | "alias": "# cores", 1878 | "dsType": "influxdb", 1879 | "groupBy": [ 1880 | { 1881 | "params": [ 1882 | "$interval" 1883 | ], 1884 | "type": "time" 1885 | }, 1886 | { 1887 | "params": [ 1888 | "host" 1889 | ], 1890 | "type": "tag" 1891 | }, 1892 | { 1893 | "params": [ 1894 | "null" 1895 | ], 1896 | "type": "fill" 1897 | } 1898 | ], 1899 | "hide": false, 1900 | "measurement": "system", 1901 | "policy": "default", 1902 | "refId": "B", 1903 | "resultFormat": "time_series", 1904 | "select": [ 1905 | [ 1906 | { 1907 | "params": [ 1908 | "n_cpus" 1909 | ], 1910 | "type": "field" 1911 | }, 1912 | { 1913 | "params": [], 1914 | "type": "mean" 1915 | } 1916 | ] 1917 | ], 1918 | "tags": [ 1919 | { 1920 | "key": "host", 1921 | "operator": "=~", 1922 | "value": "/^$host$/" 1923 | } 1924 | ] 1925 | }, 1926 | { 1927 | "alias": "load (5m)", 1928 | "dsType": "influxdb", 1929 | "groupBy": [ 1930 | { 1931 | "params": [ 1932 | "$interval" 1933 | ], 1934 | "type": "time" 1935 | }, 1936 | { 1937 | "params": [ 1938 | "host" 1939 | ], 1940 | "type": "tag" 1941 | }, 1942 | { 1943 | "params": [ 1944 | "null" 1945 | ], 1946 | "type": "fill" 1947 | } 1948 | ], 1949 | "measurement": "system", 1950 | "policy": "default", 1951 | "refId": "C", 1952 | "resultFormat": "time_series", 1953 | "select": [ 1954 | [ 1955 | { 1956 | "params": [ 1957 | "load5" 1958 | ], 1959 | "type": "field" 1960 | }, 1961 | { 1962 | "params": [], 1963 | "type": "mean" 1964 | } 1965 | ] 1966 | ], 1967 | "tags": [ 1968 | { 1969 | "key": "host", 1970 | "operator": "=~", 1971 | "value": "/^$host$/" 1972 | } 1973 | ] 1974 | } 1975 | ], 1976 | "thresholds": [], 1977 | "timeFrom": null, 1978 | "timeShift": null, 1979 | "title": "system: load (5m)", 1980 | "tooltip": { 1981 | "msResolution": false, 1982 | "shared": true, 1983 | "sort": 0, 1984 | "value_type": "individual" 1985 | }, 1986 | "type": "graph", 1987 | "xaxis": { 1988 | "mode": "time", 1989 | "name": null, 1990 | "show": true, 1991 | "values": [] 1992 | }, 1993 | "yaxes": [ 1994 | { 1995 | "format": "short", 1996 | "label": null, 1997 | "logBase": 1, 1998 | "max": null, 1999 | "min": "0", 2000 | "show": true 2001 | }, 2002 | { 2003 | "format": "short", 2004 | "label": null, 2005 | "logBase": 1, 2006 | "max": null, 2007 | "min": null, 2008 | "show": false 2009 | } 2010 | ] 2011 | } 2012 | ], 2013 | "repeat": null, 2014 | "repeatIteration": null, 2015 | "repeatRowId": null, 2016 | "showTitle": false, 2017 | "title": "Dashboard Row", 2018 | "titleSize": "h6" 2019 | } 2020 | ], 2021 | "schemaVersion": 14, 2022 | "style": "dark", 2023 | "tags": [], 2024 | "templating": { 2025 | "list": [ 2026 | { 2027 | "allValue": null, 2028 | "current": {}, 2029 | "datasource": "${DS_SERVERMONITOR}", 2030 | "hide": 0, 2031 | "includeAll": false, 2032 | "label": null, 2033 | "multi": false, 2034 | "name": "host", 2035 | "options": [], 2036 | "query": "SHOW TAG VALUES FROM system WITH KEY = \"host\"", 2037 | "refresh": 1, 2038 | "regex": "", 2039 | "sort": 1, 2040 | "tagValuesQuery": null, 2041 | "tags": [], 2042 | "tagsQuery": null, 2043 | "type": "query", 2044 | "useTags": false 2045 | } 2046 | ] 2047 | }, 2048 | "time": { 2049 | "from": "2017-09-26T06:39:12.623Z", 2050 | "to": "2017-09-26T12:28:44.516Z" 2051 | }, 2052 | "timepicker": { 2053 | "refresh_intervals": [ 2054 | "5s", 2055 | "10s", 2056 | "30s", 2057 | "1m", 2058 | "5m", 2059 | "15m", 2060 | "30m", 2061 | "1h", 2062 | "2h", 2063 | "1d" 2064 | ], 2065 | "time_options": [ 2066 | "5m", 2067 | "15m", 2068 | "1h", 2069 | "6h", 2070 | "12h", 2071 | "24h", 2072 | "2d", 2073 | "7d", 2074 | "30d" 2075 | ] 2076 | }, 2077 | "timezone": "browser", 2078 | "title": "Linux host", 2079 | "version": 32, 2080 | "description": "(\"server single\")" 2081 | } -------------------------------------------------------------------------------- /tests/test_query.py: -------------------------------------------------------------------------------- 1 | from jsonnet_utils.utils import search_prometheus_metrics 2 | 3 | from math import floor 4 | 5 | import logging 6 | 7 | logging.basicConfig( 8 | format="%(asctime)s [%(levelname)-5.5s] %(message)s", 9 | level=logging.INFO, 10 | handlers=[logging.StreamHandler()], 11 | ) 12 | 13 | test_queries = [ 14 | { 15 | "query": """ 16 | ALERTS{alertstate="firing", cluster="cluster"} 17 | """, 18 | "result": ["ALERTS"], 19 | }, 20 | { 21 | "query": '(count(ALERTS{alertstate="firing", cluster_name="cluster}) by (cluster_name)) or (sum(up{job="federate", cluster_name="cluster}) by (cluster_name) - 1)', 22 | "result": ["ALERTS", "up"], 23 | }, 24 | { 25 | "query": '1 - sum(:node_memory_MemFreeCachedBuffers:sum{cluster_name=~"cluster}) / sum(:node_memory_MemTotal:sum{cluster_name=~"cluster})', 26 | "result": [ 27 | ":node_memory_MemTotal:sum", 28 | ":node_memory_MemFreeCachedBuffers:sum", 29 | ], 30 | }, 31 | { 32 | "query": 'node:node_cpu_utilisation:avg1m{cluster_name="cluster"} * node:node_num_cpu:sum{cluster_name="cluster"} / scalar(sum(node:node_num_cpu:sum{cluster_name="cluster"}))', 33 | "result": [ 34 | "node:node_cpu_utilisation:avg1m", 35 | "node:node_num_cpu:sum", 36 | "node:node_num_cpu:sum", 37 | ], 38 | }, 39 | { 40 | "query": 'sum(cluster_services:healthy_total{cluster_name=~"^gc[0-9].*"}) by (cluster_name)', 41 | "result": ["cluster_services:healthy_total"], 42 | }, 43 | { 44 | "query": 'max(node_load1{job="kubernetes-node-exporter", cluster_name="cluster", instance="instance"})', 45 | "result": ["node_load1"], 46 | }, 47 | { 48 | "query": """ 49 | # test bla bla bla 50 | sum( 51 | label_replace( 52 | namespace_pod_name_container_name:container_cpu_usage_seconds_total:sum_rate{label="cluster", namespace="$namespace"}, 53 | "pod", "$1", "pod_name", "(.*)" 54 | ) * on(namespace,pod) group_left(workload, workload_type) mixin_pod_workload{label="cluster", namespace="namespace", workload="workload", workload_type="type"} 55 | ) by (pod) 56 | """, 57 | "result": [ 58 | "mixin_pod_workload", 59 | "namespace_pod_name_container_name:container_cpu_usage_seconds_total:sum_rate", 60 | ], 61 | }, 62 | ] 63 | 64 | for test_query in test_queries: 65 | logging.info("Testing ...\n {}".format(test_query["query"])) 66 | metrics = search_prometheus_metrics(test_query["query"]) 67 | if set(metrics) == set(test_query["result"]): 68 | logging.info("OK, found: {}\n".format(set(metrics))) 69 | else: 70 | logging.info( 71 | "Failed, found: {}, expected: {}\n".format( 72 | set(metrics), set(test_query["result"]) 73 | ) 74 | ) 75 | -------------------------------------------------------------------------------- /vendor/grafana-builder/grafana.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | dashboard( 3 | title, 4 | uid='', 5 | style='dark', 6 | tags=[], 7 | graphTooltip='default' 8 | ):: { 9 | // Stuff that isn't materialised. 10 | _nextPanel:: 0, 11 | addRow(row):: self { 12 | // automatically number panels in added rows. 13 | local n = std.length(row.panels), 14 | local nextPanel = super._nextPanel, 15 | local panels = std.makeArray(n, function(i) 16 | row.panels[i] { id: nextPanel + i }), 17 | 18 | _nextPanel: nextPanel + n, 19 | rows+: [row { panels: panels }], 20 | }, 21 | 22 | addTemplate(name, metric_name, label_name):: self { 23 | templating+: { 24 | list+: [{ 25 | allValue: null, 26 | current: { 27 | text: 'prod', 28 | value: 'prod', 29 | }, 30 | datasource: '$datasource', 31 | hide: 0, 32 | includeAll: false, 33 | label: name, 34 | multi: false, 35 | name: name, 36 | options: [], 37 | query: 'label_values(%s, %s)' % [metric_name, label_name], 38 | refresh: 1, 39 | regex: '', 40 | sort: 2, 41 | tagValuesQuery: '', 42 | tags: [], 43 | tagsQuery: '', 44 | type: 'query', 45 | useTags: false, 46 | }], 47 | }, 48 | }, 49 | 50 | addMultiTemplate(name, metric_name, label_name):: self { 51 | templating+: { 52 | list+: [{ 53 | allValue: null, 54 | current: { 55 | selected: true, 56 | text: 'All', 57 | value: '$__all', 58 | }, 59 | datasource: '$datasource', 60 | hide: 0, 61 | includeAll: true, 62 | label: name, 63 | multi: true, 64 | name: name, 65 | options: [], 66 | query: 'label_values(%s, %s)' % [metric_name, label_name], 67 | refresh: 1, 68 | regex: '', 69 | sort: 2, 70 | tagValuesQuery: '', 71 | tags: [], 72 | tagsQuery: '', 73 | type: 'query', 74 | useTags: false, 75 | }], 76 | }, 77 | }, 78 | 79 | // Stuff that is materialised. 80 | uid: uid, 81 | annotations: { 82 | list: [], 83 | }, 84 | hideControls: false, 85 | links: [], 86 | rows: [], 87 | schemaVersion: 14, 88 | style: style, 89 | tags: tags, 90 | editable: true, 91 | gnetId: null, 92 | graphTooltip: 93 | if graphTooltip == 'shared_tooltip' then 2 94 | else if graphTooltip == 'shared_crosshair' then 1 95 | else if graphTooltip == 'default' then 0 96 | else graphTooltip, 97 | templating: { 98 | list: [ 99 | { 100 | current: { 101 | text: 'Prometheus', 102 | value: 'Prometheus', 103 | }, 104 | hide: 0, 105 | label: null, 106 | name: 'datasource', 107 | options: [], 108 | query: 'prometheus', 109 | refresh: 1, 110 | regex: '', 111 | type: 'datasource', 112 | }, 113 | ], 114 | }, 115 | time: { 116 | from: 'now-1h', 117 | to: 'now', 118 | }, 119 | refresh: '10s', 120 | timepicker: { 121 | refresh_intervals: [ 122 | '5s', 123 | '10s', 124 | '30s', 125 | '1m', 126 | '5m', 127 | '15m', 128 | '30m', 129 | '1h', 130 | '2h', 131 | '1d', 132 | ], 133 | time_options: [ 134 | '5m', 135 | '15m', 136 | '1h', 137 | '6h', 138 | '12h', 139 | '24h', 140 | '2d', 141 | '7d', 142 | '30d', 143 | ], 144 | }, 145 | timezone: 'utc', 146 | title: title, 147 | version: 0, 148 | }, 149 | 150 | row(title, repeat=null, showTitle=true, height='250px'):: { 151 | _panels:: [], 152 | addPanel(panel):: self { 153 | _panels+: [panel], 154 | }, 155 | 156 | panels: 157 | // Automatically distribute panels within a row. 158 | local n = std.length(self._panels); 159 | [ 160 | p { span: std.floor(12 / n) } 161 | for p in self._panels 162 | ], 163 | 164 | collapse: false, 165 | height: height, 166 | repeat: repeat, 167 | repeatIteration: null, 168 | repeatRowId: null, 169 | showTitle: showTitle, 170 | title: title, 171 | titleSize: 'h6', 172 | }, 173 | 174 | panel(title, height='200px'):: { 175 | aliasColors: {}, 176 | bars: false, 177 | dashLength: 10, 178 | dashes: false, 179 | datasource: '$datasource', 180 | fill: 1, 181 | height: height, 182 | legend: { 183 | avg: false, 184 | current: false, 185 | max: false, 186 | min: false, 187 | show: true, 188 | total: false, 189 | values: false, 190 | }, 191 | lines: true, 192 | linewidth: 1, 193 | links: [], 194 | nullPointMode: 'null as zero', 195 | percentage: false, 196 | pointradius: 5, 197 | points: false, 198 | renderer: 'flot', 199 | seriesOverrides: [], 200 | spaceLength: 10, 201 | span: 6, 202 | stack: false, 203 | steppedLine: false, 204 | targets: [], 205 | thresholds: [], 206 | timeFrom: null, 207 | timeShift: null, 208 | title: title, 209 | tooltip: { 210 | shared: true, 211 | sort: 0, 212 | value_type: 'individual', 213 | }, 214 | type: 'graph', 215 | xaxis: { 216 | buckets: null, 217 | mode: 'time', 218 | name: null, 219 | show: true, 220 | values: [], 221 | }, 222 | yaxes: $.yaxes('short'), 223 | }, 224 | 225 | queryPanel(queries, legends, legendLink=null):: { 226 | 227 | local qs = 228 | if std.type(queries) == 'string' 229 | then [queries] 230 | else queries, 231 | local ls = 232 | if std.type(legends) == 'string' 233 | then [legends] 234 | else legends, 235 | 236 | local qsandls = if std.length(ls) == std.length(qs) 237 | then std.makeArray(std.length(qs), function(x) { q: qs[x], l: ls[x] }) 238 | else error 'length of queries is not equal to length of legends', 239 | 240 | targets+: [ 241 | { 242 | legendLink: legendLink, 243 | expr: ql.q, 244 | format: 'time_series', 245 | intervalFactor: 2, 246 | legendFormat: ql.l, 247 | step: 10, 248 | } 249 | for ql in qsandls 250 | ], 251 | }, 252 | 253 | statPanel(query, format='percentunit'):: { 254 | type: 'singlestat', 255 | thresholds: '70,80', 256 | format: format, 257 | targets: [ 258 | { 259 | expr: query, 260 | format: 'time_series', 261 | instant: true, 262 | intervalFactor: 2, 263 | refId: 'A', 264 | }, 265 | ], 266 | }, 267 | 268 | tablePanel(queries, labelStyles):: { 269 | local qs = 270 | if std.type(queries) == 'string' 271 | then [queries] 272 | else queries, 273 | 274 | local style(labelStyle) = 275 | if std.type(labelStyle) == 'string' 276 | then { 277 | alias: labelStyle, 278 | colorMode: null, 279 | colors: [], 280 | dateFormat: 'YYYY-MM-DD HH:mm:ss', 281 | decimals: 2, 282 | thresholds: [], 283 | type: 'string', 284 | unit: 'short', 285 | } 286 | else { 287 | alias: labelStyle.alias, 288 | colorMode: null, 289 | colors: [], 290 | dateFormat: 'YYYY-MM-DD HH:mm:ss', 291 | decimals: 2, 292 | thresholds: [], 293 | type: if std.objectHas(labelStyle, 'type') then labelStyle.type else 'number', 294 | unit: if std.objectHas(labelStyle, 'unit') then labelStyle.unit else 'short', 295 | link: std.objectHas(labelStyle, 'link'), 296 | linkTooltip: 'Drill down', 297 | linkUrl: if std.objectHas(labelStyle, 'link') then labelStyle.link else '', 298 | }, 299 | 300 | _styles:: { 301 | // By default hide time. 302 | Time: { 303 | alias: 'Time', 304 | dateFormat: 'YYYY-MM-DD HH:mm:ss', 305 | type: 'hidden', 306 | }, 307 | } + { 308 | [label]: style(labelStyles[label]) 309 | for label in std.objectFields(labelStyles) 310 | }, 311 | 312 | styles: [ 313 | self._styles[pattern] { pattern: pattern } 314 | for pattern in std.objectFields(self._styles) 315 | ] + [style('') + { pattern: '/.*/' }], 316 | 317 | transform: 'table', 318 | type: 'table', 319 | targets: [ 320 | { 321 | expr: qs[i], 322 | format: 'table', 323 | instant: true, 324 | intervalFactor: 2, 325 | legendFormat: '', 326 | step: 10, 327 | refId: std.char(65 + i), 328 | } 329 | for i in std.range(0, std.length(qs) - 1) 330 | ], 331 | }, 332 | 333 | stack:: { 334 | stack: true, 335 | fill: 10, 336 | linewidth: 0, 337 | }, 338 | 339 | yaxes(args):: 340 | local format = if std.type(args) == 'string' then args else null; 341 | local options = if std.type(args) == 'object' then args else {}; 342 | [ 343 | { 344 | format: format, 345 | label: null, 346 | logBase: 1, 347 | max: null, 348 | min: 0, 349 | show: true, 350 | } + options, 351 | { 352 | format: 'short', 353 | label: null, 354 | logBase: 1, 355 | max: null, 356 | min: null, 357 | show: false, 358 | }, 359 | ], 360 | 361 | qpsPanel(selector):: { 362 | aliasColors: { 363 | '1xx': '#EAB839', 364 | '2xx': '#7EB26D', 365 | '3xx': '#6ED0E0', 366 | '4xx': '#EF843C', 367 | '5xx': '#E24D42', 368 | success: '#7EB26D', 369 | 'error': '#E24D42', 370 | }, 371 | targets: [ 372 | { 373 | expr: 'sum by (status) (label_replace(label_replace(rate(' + selector + '[1m]),' 374 | + ' "status", "${1}xx", "status_code", "([0-9]).."),' 375 | + ' "status", "${1}", "status_code", "([a-z]+)"))', 376 | format: 'time_series', 377 | intervalFactor: 2, 378 | legendFormat: '{{status}}', 379 | refId: 'A', 380 | step: 10, 381 | }, 382 | ], 383 | } + $.stack, 384 | 385 | latencyPanel(metricName, selector, multiplier='1e3'):: { 386 | nullPointMode: 'null as zero', 387 | targets: [ 388 | { 389 | expr: 'histogram_quantile(0.99, sum(rate(%s_bucket%s[5m])) by (le)) * %s' % [metricName, selector, multiplier], 390 | format: 'time_series', 391 | intervalFactor: 2, 392 | legendFormat: '99th Percentile', 393 | refId: 'A', 394 | step: 10, 395 | }, 396 | { 397 | expr: 'histogram_quantile(0.50, sum(rate(%s_bucket%s[5m])) by (le)) * %s' % [metricName, selector, multiplier], 398 | format: 'time_series', 399 | intervalFactor: 2, 400 | legendFormat: '50th Percentile', 401 | refId: 'B', 402 | step: 10, 403 | }, 404 | { 405 | expr: 'sum(rate(%s_sum%s[5m])) * %s / sum(rate(%s_count%s[5m]))' % [metricName, selector, multiplier, metricName, selector], 406 | format: 'time_series', 407 | intervalFactor: 2, 408 | legendFormat: 'Average', 409 | refId: 'C', 410 | step: 10, 411 | }, 412 | ], 413 | yaxes: $.yaxes('ms'), 414 | }, 415 | 416 | selector:: { 417 | eq(label, value):: { label: label, op: '=', value: value }, 418 | neq(label, value):: { label: label, op: '!=', value: value }, 419 | re(label, value):: { label: label, op: '=~', value: value }, 420 | nre(label, value):: { label: label, op: '!~', value: value }, 421 | }, 422 | 423 | toPrometheusSelector(selector):: 424 | local pairs = [ 425 | '%(label)s%(op)s"%(value)s"' % matcher 426 | for matcher in selector 427 | ]; 428 | '{%s}' % std.join(', ', pairs), 429 | } 430 | -------------------------------------------------------------------------------- /vendor/grafonnet/alert_condition.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Returns a new condition of alert of graph panel. 4 | * Currently the only condition type that exists is a Query condition 5 | * that allows to specify a query letter, time range and an aggregation function. 6 | * 7 | * @param evaluatorParams Value of threshold 8 | * @param evaluatorType Type of threshold 9 | * @param operatorType Operator between conditions 10 | * @param queryRefId The letter defines what query to execute from the Metrics tab 11 | * @param queryTimeStart Begging of time range 12 | * @param queryTimeEnd End of time range 13 | * @param reducerParams Params of an aggregation function 14 | * @param reducerType Name of an aggregation function 15 | * @return A json that represents a condition of alert 16 | */ 17 | new( 18 | evaluatorParams=[], 19 | evaluatorType='gt', 20 | operatorType='and', 21 | queryRefId='A', 22 | queryTimeEnd='now', 23 | queryTimeStart='5m', 24 | reducerParams=[], 25 | reducerType='avg', 26 | ):: 27 | { 28 | evaluator: { 29 | params: if std.type(evaluatorParams) == 'array' then evaluatorParams else [evaluatorParams], 30 | type: evaluatorType, 31 | }, 32 | operator: { 33 | type: operatorType, 34 | }, 35 | query: { 36 | params: [queryRefId, queryTimeStart, queryTimeEnd], 37 | }, 38 | reducer: { 39 | params: if std.type(reducerParams) == 'array' then reducerParams else [reducerParams], 40 | type: reducerType, 41 | }, 42 | type: 'query', 43 | }, 44 | } 45 | -------------------------------------------------------------------------------- /vendor/grafonnet/annotation.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | default:: 3 | { 4 | builtIn: 1, 5 | datasource: '-- Grafana --', 6 | enable: true, 7 | hide: true, 8 | iconColor: 'rgba(0, 211, 255, 1)', 9 | name: 'Annotations & Alerts', 10 | type: 'dashboard', 11 | }, 12 | datasource( 13 | name, 14 | datasource, 15 | expr=null, 16 | enable=true, 17 | hide=false, 18 | iconColor='rgba(255, 96, 96, 1)', 19 | tags=[], 20 | type='tags', 21 | builtIn=null, 22 | ):: 23 | { 24 | datasource: datasource, 25 | enable: enable, 26 | [if expr != null then 'expr']: expr, 27 | hide: hide, 28 | iconColor: iconColor, 29 | name: name, 30 | showIn: 0, 31 | tags: tags, 32 | type: type, 33 | [if builtIn != null then 'builtIn']: builtIn, 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /vendor/grafonnet/cloudwatch.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Return a CloudWatch Target 4 | * 5 | * @param region 6 | * @param namespace 7 | * @param metric 8 | * @param datasource 9 | * @param statistic 10 | * @param alias 11 | * @param highResolution 12 | * @param period 13 | * @param dimensions 14 | 15 | * @return Panel target 16 | */ 17 | 18 | target( 19 | region, 20 | namespace, 21 | metric, 22 | datasource=null, 23 | statistic='Average', 24 | alias=null, 25 | highResolution=false, 26 | period='1m', 27 | dimensions={} 28 | ):: { 29 | region: region, 30 | namespace: namespace, 31 | metricName: metric, 32 | [if datasource != null then 'datasource']: datasource, 33 | statistics: [statistic], 34 | [if alias != null then 'alias']: alias, 35 | highResolution: highResolution, 36 | period: period, 37 | dimensions: dimensions, 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /vendor/grafonnet/dashboard.libsonnet: -------------------------------------------------------------------------------- 1 | local timepickerlib = import 'timepicker.libsonnet'; 2 | 3 | { 4 | new( 5 | title, 6 | editable=false, 7 | style='dark', 8 | tags=[], 9 | time_from='now-6h', 10 | time_to='now', 11 | timezone='browser', 12 | refresh='', 13 | timepicker=timepickerlib.new(), 14 | graphTooltip='default', 15 | hideControls=false, 16 | schemaVersion=14, 17 | uid='', 18 | description=null, 19 | ):: { 20 | local it = self, 21 | _annotations:: [], 22 | [if uid != '' then 'uid']: uid, 23 | editable: editable, 24 | [if description != null then 'description']: description, 25 | gnetId: null, 26 | graphTooltip: 27 | if graphTooltip == 'shared_tooltip' then 2 28 | else if graphTooltip == 'shared_crosshair' then 1 29 | else if graphTooltip == 'default' then 0 30 | else graphTooltip, 31 | hideControls: hideControls, 32 | id: null, 33 | links: [], 34 | panels:: [], 35 | refresh: refresh, 36 | rows: [], 37 | schemaVersion: schemaVersion, 38 | style: style, 39 | tags: tags, 40 | time: { 41 | from: time_from, 42 | to: time_to, 43 | }, 44 | timezone: timezone, 45 | timepicker: timepicker, 46 | title: title, 47 | version: 0, 48 | addAnnotation(annotation):: self { 49 | _annotations+:: [annotation], 50 | }, 51 | addTemplate(t):: self { 52 | templates+: [t], 53 | }, 54 | templates:: [], 55 | annotations: { list: it._annotations }, 56 | templating: { list: it.templates }, 57 | _nextPanel:: 2, 58 | addRow(row):: 59 | self { 60 | // automatically number panels in added rows. 61 | // https://github.com/kausalco/public/blob/master/klumps/grafana.libsonnet 62 | local n = std.length(row.panels), 63 | local nextPanel = super._nextPanel, 64 | local panels = std.makeArray(n, function(i) 65 | row.panels[i] { id: nextPanel + i }), 66 | 67 | _nextPanel: nextPanel + n, 68 | rows+: [row { panels: panels }], 69 | }, 70 | addPanels(newpanels):: 71 | self { 72 | // automatically number panels in added rows. 73 | // https://github.com/kausalco/public/blob/master/klumps/grafana.libsonnet 74 | local n = std.foldl(function(numOfPanels, p) 75 | (if 'panels' in p then 76 | numOfPanels + 1 + std.length(p.panels) 77 | else 78 | numOfPanels + 1), newpanels, 0), 79 | local nextPanel = super._nextPanel, 80 | local _panels = std.makeArray( 81 | std.length(newpanels), function(i) 82 | newpanels[i] { 83 | id: nextPanel + ( 84 | if i == 0 then 85 | 0 86 | else 87 | if 'panels' in _panels[i - 1] then 88 | (_panels[i - 1].id - nextPanel) + 1 + std.length(_panels[i - 1].panels) 89 | else 90 | (_panels[i - 1].id - nextPanel) + 1 91 | 92 | ), 93 | [if 'panels' in newpanels[i] then 'panels']: std.makeArray( 94 | std.length(newpanels[i].panels), function(j) 95 | newpanels[i].panels[j] { 96 | id: 1 + j + 97 | nextPanel + ( 98 | if i == 0 then 99 | 0 100 | else 101 | if 'panels' in _panels[i - 1] then 102 | (_panels[i - 1].id - nextPanel) + 1 + std.length(_panels[i - 1].panels) 103 | else 104 | (_panels[i - 1].id - nextPanel) + 1 105 | 106 | ), 107 | } 108 | ), 109 | } 110 | ), 111 | 112 | _nextPanel: nextPanel + n, 113 | panels+::: _panels, 114 | }, 115 | addPanel(panel, gridPos):: self + self.addPanels([panel { gridPos: gridPos }]), 116 | addRows(rows):: std.foldl(function(d, row) d.addRow(row), rows, self), 117 | addLink(link):: self { 118 | links+: [link], 119 | }, 120 | }, 121 | } 122 | -------------------------------------------------------------------------------- /vendor/grafonnet/elasticsearch.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | target( 3 | query, 4 | id=null, 5 | datasource=null, 6 | metrics=[{ 7 | field: "value", 8 | id: null, 9 | type: "percentiles", 10 | settings: { 11 | percents: [ 12 | "90", 13 | ], 14 | }, 15 | }], 16 | bucketAggs=[{ 17 | field: "timestamp", 18 | id: null, 19 | type: "date_histogram", 20 | settings: { 21 | interval: "1s", 22 | min_doc_count: 0, 23 | trimEdges: 0 24 | }, 25 | }], 26 | timeField, 27 | alias=null, 28 | ):: { 29 | [if datasource != null then 'datasource']: datasource, 30 | query: query, 31 | id: id, 32 | timeField: timeField, 33 | bucketAggs: bucketAggs, 34 | metrics: metrics, 35 | alias: alias 36 | // TODO: generate bucket ids 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/grafonnet/grafana.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | dashboard:: import 'dashboard.libsonnet', 3 | template:: import 'template.libsonnet', 4 | text:: import 'text.libsonnet', 5 | timepicker:: import 'timepicker.libsonnet', 6 | row:: import 'row.libsonnet', 7 | link:: import 'link.libsonnet', 8 | annotation:: import 'annotation.libsonnet', 9 | graphPanel:: import 'graph_panel.libsonnet', 10 | tablePanel:: import 'table_panel.libsonnet', 11 | singlestat:: import 'singlestat.libsonnet', 12 | influxdb:: import 'influxdb.libsonnet', 13 | prometheus:: import 'prometheus.libsonnet', 14 | sql:: import 'sql.libsonnet', 15 | graphite:: import 'graphite.libsonnet', 16 | alertCondition:: import 'alert_condition.libsonnet', 17 | cloudwatch:: import 'cloudwatch.libsonnet', 18 | elasticsearch:: import 'elasticsearch.libsonnet', 19 | } 20 | -------------------------------------------------------------------------------- /vendor/grafonnet/graph_panel.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Returns a new graph panel that can be added in a row. 4 | * It requires the graph panel plugin in grafana, which is built-in. 5 | * 6 | * @param title The title of the graph panel. 7 | * @param span Width of the panel 8 | * @param datasource Datasource 9 | * @param fill Fill, integer from 0 to 10 10 | * @param linewidth Line Width, integer from 0 to 10 11 | * @param decimals Override automatic decimal precision for legend and tooltip. If null, not added to the json output. 12 | * @param min_span Min span 13 | * @param format Unit of the Y axes 14 | * @param formatY1 Unit of the first Y axe 15 | * @param formatY2 Unit of the second Y axe 16 | * @param min Min of the Y axes 17 | * @param max Max of the Y axes 18 | * @param x_axis_mode X axis mode, one of [time, series, histogram] 19 | * @param x_axis_values Chosen value of series, one of [avg, min, max, total, count] 20 | * @param lines Display lines, boolean 21 | * @param points Display points, boolean 22 | * @param pointradius Radius of the points, allowed values are 0.5 or [1 ... 10] with step 1 23 | * @param bars Display bars, boolean 24 | * @param dashes Display line as dashes 25 | * @param stack Stack values 26 | * @param repeat Variable used to repeat the graph panel 27 | * @param legend_show Show legend 28 | * @param legend_values Show values in legend 29 | * @param legend_min Show min in legend 30 | * @param legend_max Show max in legend 31 | * @param legend_current Show current in legend 32 | * @param legend_total Show total in legend 33 | * @param legend_avg Show average in legend 34 | * @param legend_alignAsTable Show legend as table 35 | * @param legend_rightSide Show legend to the right 36 | * @param legend_sort Sort order of legend 37 | * @param legend_sortDesc Sort legend descending 38 | * @param aliasColors Define color mappings for graphs 39 | * @param valueType Type of tooltip value 40 | * @param thresholds Configuration of graph thresholds 41 | * @param logBase1Y Value of logarithm base of the first Y axe 42 | * @param logBase2Y Value of logarithm base of the second Y axe 43 | * @param transparent Boolean (default: false) If set to true the panel will be transparent 44 | * @return A json that represents a graph panel 45 | */ 46 | new( 47 | title, 48 | span=null, 49 | fill=1, 50 | linewidth=1, 51 | decimals=null, 52 | description=null, 53 | min_span=null, 54 | format='short', 55 | formatY1=null, 56 | formatY2=null, 57 | min=null, 58 | max=null, 59 | x_axis_mode='time', 60 | x_axis_values='total', 61 | lines=true, 62 | datasource=null, 63 | points=false, 64 | pointradius=5, 65 | bars=false, 66 | height=null, 67 | nullPointMode='null', 68 | dashes=false, 69 | stack=false, 70 | repeat=null, 71 | repeatDirection=null, 72 | sort=0, 73 | show_xaxis=true, 74 | legend_show=true, 75 | legend_values=false, 76 | legend_min=false, 77 | legend_max=false, 78 | legend_current=false, 79 | legend_total=false, 80 | legend_avg=false, 81 | legend_alignAsTable=false, 82 | legend_rightSide=false, 83 | legend_hideEmpty=null, 84 | legend_hideZero=null, 85 | legend_sort=null, 86 | legend_sortDesc=null, 87 | aliasColors={}, 88 | thresholds=[], 89 | logBase1Y=1, 90 | logBase2Y=1, 91 | transparent=false, 92 | value_type='individual' 93 | ):: { 94 | title: title, 95 | [if span != null then 'span']: span, 96 | [if min_span != null then 'minSpan']: min_span, 97 | type: 'graph', 98 | datasource: datasource, 99 | targets: [ 100 | ], 101 | [if description != null then 'description']: description, 102 | [if height != null then 'height']: height, 103 | renderer: 'flot', 104 | yaxes: [ 105 | self.yaxe(if formatY1 != null then formatY1 else format, min, max, decimals=decimals, logBase=logBase1Y), 106 | self.yaxe(if formatY2 != null then formatY2 else format, min, max, decimals=decimals, logBase=logBase2Y), 107 | ], 108 | xaxis: { 109 | show: show_xaxis, 110 | mode: x_axis_mode, 111 | name: null, 112 | values: if x_axis_mode == 'series' then [x_axis_values] else [], 113 | buckets: null, 114 | }, 115 | lines: lines, 116 | fill: fill, 117 | linewidth: linewidth, 118 | dashes: dashes, 119 | dashLength: 10, 120 | spaceLength: 10, 121 | points: points, 122 | pointradius: pointradius, 123 | bars: bars, 124 | stack: stack, 125 | percentage: false, 126 | legend: { 127 | show: legend_show, 128 | values: legend_values, 129 | min: legend_min, 130 | max: legend_max, 131 | current: legend_current, 132 | total: legend_total, 133 | alignAsTable: legend_alignAsTable, 134 | rightSide: legend_rightSide, 135 | avg: legend_avg, 136 | [if legend_hideEmpty != null then 'hideEmpty']: legend_hideEmpty, 137 | [if legend_hideZero != null then 'hideZero']: legend_hideZero, 138 | [if legend_sort != null then 'sort']: legend_sort, 139 | [if legend_sortDesc != null then 'sortDesc']: legend_sortDesc, 140 | }, 141 | nullPointMode: nullPointMode, 142 | steppedLine: false, 143 | tooltip: { 144 | value_type: value_type, 145 | shared: true, 146 | sort: if sort == 'decreasing' then 2 else if sort == 'increasing' then 1 else sort, 147 | }, 148 | timeFrom: null, 149 | timeShift: null, 150 | [if transparent == true then 'transparent']: transparent, 151 | aliasColors: aliasColors, 152 | repeat: repeat, 153 | [if repeatDirection != null then 'repeatDirection']: repeatDirection, 154 | seriesOverrides: [], 155 | thresholds: thresholds, 156 | links: [], 157 | yaxe( 158 | format='short', 159 | min=null, 160 | max=null, 161 | label=null, 162 | show=true, 163 | logBase=1, 164 | decimals=null, 165 | ):: { 166 | label: label, 167 | show: show, 168 | logBase: logBase, 169 | min: min, 170 | max: max, 171 | format: format, 172 | [if decimals != null then 'decimals']: decimals, 173 | }, 174 | _nextTarget:: 0, 175 | addTarget(target):: self { 176 | // automatically ref id in added targets. 177 | // https://github.com/kausalco/public/blob/master/klumps/grafana.libsonnet 178 | local nextTarget = super._nextTarget, 179 | _nextTarget: nextTarget + 1, 180 | targets+: [target { refId: std.char(std.codepoint('A') + nextTarget) }], 181 | }, 182 | addTargets(targets):: std.foldl(function(p, t) p.addTarget(t), targets, self), 183 | _nextSeriesOverride:: 0, 184 | addSeriesOverride(override):: self { 185 | local nextOverride = super._nextSerieOverride, 186 | _nextSeriesOverride: nextOverride + 1, 187 | seriesOverrides+: [override], 188 | }, 189 | resetYaxes():: self { 190 | yaxes: [], 191 | _nextYaxis:: 0, 192 | }, 193 | _nextYaxis:: 0, 194 | addYaxis( 195 | format='short', 196 | min=null, 197 | max=null, 198 | label=null, 199 | show=true, 200 | logBase=1, 201 | decimals=null, 202 | ):: self { 203 | local nextYaxis = super._nextYaxis, 204 | _nextYaxis: nextYaxis + 1, 205 | yaxes+: [self.yaxe(format, min, max, label, show, logBase, decimals)], 206 | }, 207 | addAlert( 208 | name, 209 | executionErrorState='alerting', 210 | frequency='60s', 211 | handler=1, 212 | noDataState='no_data', 213 | notifications=[], 214 | ):: self { 215 | local it = self, 216 | _conditions:: [], 217 | alert: { 218 | name: name, 219 | conditions: it._conditions, 220 | executionErrorState: executionErrorState, 221 | frequency: frequency, 222 | handler: handler, 223 | noDataState: noDataState, 224 | notifications: notifications, 225 | }, 226 | addCondition(condition):: self { 227 | _conditions+: [condition], 228 | }, 229 | addConditions(conditions):: std.foldl(function(p, c) p.addCondition(c), conditions, it), 230 | }, 231 | }, 232 | } 233 | -------------------------------------------------------------------------------- /vendor/grafonnet/graphite.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Return an Graphite Target 4 | * 5 | * @param target Graphite Query. Nested queries are possible by adding the query reference (refId). 6 | * @param targetFull Expanding the @target. Used in nested queries. 7 | * @param hide Disable query on graph. 8 | * @param textEditor Enable raw query mode. 9 | * @param datasource Datasource. 10 | 11 | * @return Panel target 12 | */ 13 | target( 14 | target, 15 | targetFull=null, 16 | hide=false, 17 | textEditor=false, 18 | datasource=null, 19 | ):: { 20 | target: target, 21 | hide: hide, 22 | textEditor: textEditor, 23 | 24 | [if targetFull != null then 'targetFull']: targetFull, 25 | [if datasource != null then 'datasource']: datasource, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /vendor/grafonnet/influxdb.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Return an InfluxDB Target 4 | * 5 | * @param query Raw InfluxQL statement 6 | * @param alias Alias By pattern 7 | * @param datasource Datasource 8 | * @param rawQuery En/Disable raw query mode 9 | * @param resultFormat Format results as 'Time series' or 'Table' 10 | 11 | * @return Panel target 12 | */ 13 | target( 14 | query, 15 | alias=null, 16 | datasource=null, 17 | rawQuery=true, 18 | resultFormat='time_series', 19 | ):: { 20 | query: query, 21 | rawQuery: rawQuery, 22 | resultFormat: resultFormat, 23 | 24 | [if alias != null then 'alias']: alias, 25 | [if datasource != null then 'datasource']: datasource, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /vendor/grafonnet/link.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | dashboards( 3 | title, 4 | tags, 5 | asDropdown=true, 6 | includeVars=false, 7 | keepTime=false, 8 | icon='external link', 9 | url='', 10 | targetBlank=false, 11 | type='dashboards', 12 | ):: 13 | { 14 | asDropdown: asDropdown, 15 | icon: icon, 16 | includeVars: includeVars, 17 | keepTime: keepTime, 18 | tags: tags, 19 | title: title, 20 | type: type, 21 | url: url, 22 | targetBlank: targetBlank, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /vendor/grafonnet/prometheus.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | target( 3 | expr, 4 | format='time_series', 5 | intervalFactor=2, 6 | legendFormat='', 7 | datasource=null, 8 | interval=null, 9 | instant=null, 10 | ):: { 11 | [if datasource != null then 'datasource']: datasource, 12 | expr: expr, 13 | format: format, 14 | intervalFactor: intervalFactor, 15 | legendFormat: legendFormat, 16 | [if interval != null then 'interval']: interval, 17 | [if instant != null then 'instant']: instant, 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /vendor/grafonnet/row.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | new( 3 | title='Dashboard Row', 4 | height=null, 5 | collapse=false, 6 | repeat=null, 7 | showTitle=null, 8 | titleSize='h6' 9 | ):: { 10 | collapse: collapse, 11 | collapsed: collapse, 12 | [if height != null then 'height']: height, 13 | panels: [], 14 | repeat: repeat, 15 | repeatIteration: null, 16 | repeatRowId: null, 17 | showTitle: 18 | if showTitle != null then 19 | showTitle 20 | else 21 | title != 'Dashboard Row', 22 | title: title, 23 | type: 'row', 24 | titleSize: titleSize, 25 | addPanels(panels):: self { 26 | panels+: panels, 27 | }, 28 | addPanel(panel, gridPos={}):: self { 29 | panels+: [panel { gridPos: gridPos }], 30 | }, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /vendor/grafonnet/singlestat.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | new( 3 | title, 4 | format='none', 5 | description='', 6 | interval=null, 7 | height=null, 8 | datasource=null, 9 | span=null, 10 | min_span=null, 11 | decimals=null, 12 | valueName='avg', 13 | valueFontSize='80%', 14 | prefixFontSize='50%', 15 | postfixFontSize='50%', 16 | mappingType=1, 17 | repeat=null, 18 | repeatDirection=null, 19 | prefix='', 20 | postfix='', 21 | colors=[ 22 | '#299c46', 23 | 'rgba(237, 129, 40, 0.89)', 24 | '#d44a3a', 25 | ], 26 | colorBackground=false, 27 | colorValue=false, 28 | thresholds='', 29 | valueMaps=[ 30 | { 31 | value: 'null', 32 | op: '=', 33 | text: 'N/A', 34 | }, 35 | ], 36 | rangeMaps=[ 37 | { 38 | from: 'null', 39 | to: 'null', 40 | text: 'N/A', 41 | }, 42 | ], 43 | transparent=null, 44 | sparklineFillColor='rgba(31, 118, 189, 0.18)', 45 | sparklineFull=false, 46 | sparklineLineColor='rgb(31, 120, 193)', 47 | sparklineShow=false, 48 | gaugeShow=false, 49 | gaugeMinValue=0, 50 | gaugeMaxValue=100, 51 | gaugeThresholdMarkers=true, 52 | gaugeThresholdLabels=false, 53 | ):: 54 | { 55 | [if height != null then 'height']: height, 56 | [if description != '' then 'description']: description, 57 | [if repeat != null then 'repeat']: repeat, 58 | [if repeatDirection != null then 'repeatDirection']: repeatDirection, 59 | [if transparent != null then 'transparent']: transparent, 60 | [if min_span != null then 'minSpan']: min_span, 61 | title: title, 62 | [if span != null then 'span']: span, 63 | type: 'singlestat', 64 | datasource: datasource, 65 | targets: [ 66 | ], 67 | links: [], 68 | [if decimals != null then 'decimals']: decimals, 69 | maxDataPoints: 100, 70 | interval: interval, 71 | cacheTimeout: null, 72 | format: format, 73 | prefix: prefix, 74 | postfix: postfix, 75 | nullText: null, 76 | valueMaps: valueMaps, 77 | mappingTypes: [ 78 | { 79 | name: 'value to text', 80 | value: 1, 81 | }, 82 | { 83 | name: 'range to text', 84 | value: 2, 85 | }, 86 | ], 87 | rangeMaps: rangeMaps, 88 | mappingType: 89 | if mappingType == 'value' 90 | then 91 | 1 92 | else if mappingType == 'range' 93 | then 94 | 2 95 | else 96 | mappingType, 97 | nullPointMode: 'connected', 98 | valueName: valueName, 99 | prefixFontSize: prefixFontSize, 100 | valueFontSize: valueFontSize, 101 | postfixFontSize: postfixFontSize, 102 | thresholds: thresholds, 103 | colorBackground: colorBackground, 104 | colorValue: colorValue, 105 | colors: colors, 106 | gauge: { 107 | show: gaugeShow, 108 | minValue: gaugeMinValue, 109 | maxValue: gaugeMaxValue, 110 | thresholdMarkers: gaugeThresholdMarkers, 111 | thresholdLabels: gaugeThresholdLabels, 112 | }, 113 | sparkline: { 114 | fillColor: sparklineFillColor, 115 | full: sparklineFull, 116 | lineColor: sparklineLineColor, 117 | show: sparklineShow, 118 | }, 119 | tableColumn: '', 120 | _nextTarget:: 0, 121 | addTarget(target):: self { 122 | local nextTarget = super._nextTarget, 123 | _nextTarget: nextTarget + 1, 124 | targets+: [target { refId: std.char(std.codepoint('A') + nextTarget) }], 125 | }, 126 | }, 127 | } 128 | -------------------------------------------------------------------------------- /vendor/grafonnet/sql.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | target( 3 | rawSql, 4 | datasource=null, 5 | format='time_series', 6 | ):: { 7 | [if datasource != null then 'datasource']: datasource, 8 | format: format, 9 | rawSql: rawSql, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /vendor/grafonnet/table_panel.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * Returns a new table panel that can be added in a row. 4 | * It requires the table panel plugin in grafana, which is built-in. 5 | * 6 | * @param title The title of the graph panel. 7 | * @param span Width of the panel 8 | * @param description Description of the panel 9 | * @param datasource Datasource 10 | * @param min_span Min span 11 | * @param styles Styles for the panel 12 | * @return A json that represents a table panel 13 | */ 14 | new( 15 | title, 16 | description=null, 17 | span=null, 18 | sort=null, 19 | min_span=null, 20 | datasource=null, 21 | columns=[], 22 | styles=[], 23 | ):: { 24 | type: 'table', 25 | title: title, 26 | columns: columns, 27 | [if sort != null then 'sort']: sort, 28 | [if span != null then 'span']: span, 29 | [if min_span != null then 'minSpan']: min_span, 30 | datasource: datasource, 31 | targets: [ 32 | ], 33 | styles: styles, 34 | [if description != null then 'description']: description, 35 | transform: 'table', 36 | _nextTarget:: 0, 37 | addTarget(target):: self { 38 | // automatically ref id in added targets. 39 | // https://github.com/kausalco/public/blob/master/klumps/grafana.libsonnet 40 | local nextTarget = super._nextTarget, 41 | _nextTarget: nextTarget + 1, 42 | targets+: [target { refId: std.char(std.codepoint('A') + nextTarget) }], 43 | }, 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /vendor/grafonnet/template.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | new( 3 | name, 4 | datasource, 5 | query, 6 | label=null, 7 | allValues=null, 8 | tagValuesQuery='', 9 | current=null, 10 | hide='', 11 | regex='', 12 | refresh='never', 13 | includeAll=false, 14 | multi=false, 15 | sort=0, 16 | ):: 17 | { 18 | allValue: allValues, 19 | current: $.current(current), 20 | datasource: datasource, 21 | includeAll: includeAll, 22 | hide: $.hide(hide), 23 | label: label, 24 | multi: multi, 25 | name: name, 26 | options: [], 27 | query: query, 28 | refresh: $.refresh(refresh), 29 | regex: regex, 30 | sort: sort, 31 | tagValuesQuery: tagValuesQuery, 32 | tags: [], 33 | tagsQuery: '', 34 | type: 'query', 35 | useTags: false, 36 | }, 37 | interval( 38 | name, 39 | query, 40 | current, 41 | hide='', 42 | label=null, 43 | auto_count=300, 44 | auto_min='10s', 45 | ):: 46 | { 47 | current: $.current(current), 48 | hide: if hide == '' then 0 else if hide == 'label' then 1 else 2, 49 | label: label, 50 | name: name, 51 | query: std.join(',', std.filter($.filterAuto, std.split(query, ','))), 52 | refresh: 2, 53 | type: 'interval', 54 | auto: std.count(std.split(query, ','), 'auto') > 0, 55 | auto_count: auto_count, 56 | auto_min: auto_min, 57 | }, 58 | hide(hide):: 59 | if hide == '' then 0 else if hide == 'label' then 1 else 2, 60 | current(current):: { 61 | [if current != null then 'text']: current, 62 | [if current != null then 'value']: if current == 'auto' then 63 | '$__auto_interval' 64 | else if current == 'all' then 65 | '$__all' 66 | else 67 | current, 68 | }, 69 | datasource( 70 | name, 71 | query, 72 | current, 73 | hide='', 74 | label=null, 75 | regex='', 76 | refresh='load', 77 | ):: { 78 | current: $.current(current), 79 | hide: $.hide(hide), 80 | label: label, 81 | name: name, 82 | options: [], 83 | query: query, 84 | refresh: $.refresh(refresh), 85 | regex: regex, 86 | type: 'datasource', 87 | }, 88 | refresh(refresh):: if refresh == 'never' 89 | then 90 | 0 91 | else if refresh == 'load' 92 | then 93 | 1 94 | else if refresh == 'time' 95 | then 96 | 2 97 | else 98 | refresh, 99 | filterAuto(str):: str != 'auto', 100 | custom( 101 | name, 102 | query, 103 | current, 104 | refresh='never', 105 | label='', 106 | valuelabels={}, 107 | hide='', 108 | ):: 109 | { 110 | allValue: null, 111 | current: { 112 | value: current, 113 | text: if current in valuelabels then valuelabels[current] else current, 114 | }, 115 | options: std.map( 116 | function(i) 117 | { 118 | text: if i in valuelabels then valuelabels[i] else i, 119 | value: i, 120 | }, std.split(query, ',') 121 | ), 122 | hide: $.hide(hide), 123 | includeAll: false, 124 | label: label, 125 | refresh: $.refresh(refresh), 126 | multi: false, 127 | name: name, 128 | query: query, 129 | type: 'custom', 130 | }, 131 | } 132 | -------------------------------------------------------------------------------- /vendor/grafonnet/text.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | new( 3 | title='', 4 | span=null, 5 | mode='markdown', 6 | content='', 7 | transparent=null, 8 | ):: 9 | { 10 | [if transparent != null then 'transparent']: transparent, 11 | title: title, 12 | [if span != null then 'span']: span, 13 | type: 'text', 14 | mode: mode, 15 | content: content, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /vendor/grafonnet/timepicker.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | new( 3 | refresh_intervals=[ 4 | '5s', 5 | '10s', 6 | '30s', 7 | '1m', 8 | '5m', 9 | '15m', 10 | '30m', 11 | '1h', 12 | '2h', 13 | '1d', 14 | ], 15 | time_options=[ 16 | '5m', 17 | '15m', 18 | '1h', 19 | '6h', 20 | '12h', 21 | '24h', 22 | '2d', 23 | '7d', 24 | '30d', 25 | ], 26 | ):: { 27 | refresh_intervals: refresh_intervals, 28 | time_options: time_options, 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /vendor/promgrafonnet/gauge.libsonnet: -------------------------------------------------------------------------------- 1 | local grafana = import 'grafonnet/grafana.libsonnet'; 2 | local singlestat = grafana.singlestat; 3 | local prometheus = grafana.prometheus; 4 | 5 | { 6 | new(title, query):: 7 | singlestat.new( 8 | title, 9 | datasource='$datasource', 10 | span=3, 11 | format='percent', 12 | valueName='current', 13 | colors=[ 14 | 'rgba(245, 54, 54, 0.9)', 15 | 'rgba(237, 129, 40, 0.89)', 16 | 'rgba(50, 172, 45, 0.97)', 17 | ], 18 | thresholds='50, 80', 19 | valueMaps=[ 20 | { 21 | op: '=', 22 | text: 'N/A', 23 | value: 'null', 24 | }, 25 | ], 26 | ) 27 | .addTarget( 28 | prometheus.target( 29 | query 30 | ) 31 | ) + { 32 | gauge: { 33 | maxValue: 100, 34 | minValue: 0, 35 | show: true, 36 | thresholdLabels: false, 37 | thresholdMarkers: true, 38 | }, 39 | withTextNullValue(text):: self { 40 | valueMaps: [ 41 | { 42 | op: '=', 43 | text: text, 44 | value: 'null', 45 | }, 46 | ], 47 | }, 48 | withSpanSize(size):: self { 49 | span: size, 50 | }, 51 | withLowerBeingBetter():: self { 52 | colors: [ 53 | 'rgba(50, 172, 45, 0.97)', 54 | 'rgba(237, 129, 40, 0.89)', 55 | 'rgba(245, 54, 54, 0.9)', 56 | ], 57 | thresholds: '80, 90', 58 | }, 59 | }, 60 | } 61 | -------------------------------------------------------------------------------- /vendor/promgrafonnet/numbersinglestat.libsonnet: -------------------------------------------------------------------------------- 1 | local grafana = import 'grafonnet/grafana.libsonnet'; 2 | local singlestat = grafana.singlestat; 3 | local prometheus = grafana.prometheus; 4 | 5 | { 6 | new(title, query):: 7 | singlestat.new( 8 | title, 9 | datasource='$datasource', 10 | span=3, 11 | valueName='current', 12 | valueMaps=[ 13 | { 14 | op: '=', 15 | text: '0', 16 | value: 'null', 17 | }, 18 | ], 19 | ) 20 | .addTarget( 21 | prometheus.target( 22 | query 23 | ) 24 | ) + { 25 | withTextNullValue(text):: self { 26 | valueMaps: [ 27 | { 28 | op: '=', 29 | text: text, 30 | value: 'null', 31 | }, 32 | ], 33 | }, 34 | withSpanSize(size):: self { 35 | span: size, 36 | }, 37 | withPostfix(postfix):: self { 38 | postfix: postfix, 39 | }, 40 | withSparkline():: self { 41 | sparkline: { 42 | show: true, 43 | lineColor: 'rgb(31, 120, 193)', 44 | fillColor: 'rgba(31, 118, 189, 0.18)', 45 | }, 46 | }, 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /vendor/promgrafonnet/promgrafonnet.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | numbersinglestat:: import 'numbersinglestat.libsonnet', 3 | gauge:: import 'gauge.libsonnet', 4 | percentlinegraph:: import 'percentlinegraph.libsonnet', 5 | } 6 | -------------------------------------------------------------------------------- /view/dag.css: -------------------------------------------------------------------------------- 1 | svg { 2 | display: block; 3 | margin: 0 auto; 4 | overflow: hidden; 5 | } 6 | 7 | .node rect { 8 | stroke: #333; 9 | stroke-width: 1.5px; 10 | fill: #fff; 11 | } 12 | 13 | .edgeLabel rect { 14 | fill: #F8F9FA; 15 | } 16 | 17 | .edgePath { 18 | stroke: #333; 19 | stroke-width: 1.5px; 20 | fill: none; 21 | } -------------------------------------------------------------------------------- /view/dag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |