From db2e1b778a127b4d595abf6d19b807924475d457 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Tue, 30 Sep 2025 18:07:57 -0400 Subject: [PATCH 01/20] SAS SpeedyStore Sample: Initial work --- samples/speedystore/README.md | 145 + .../speedystore/dashboards/clusterview.json | 2449 ++++++++++++++++ .../dashboards/detailedclusterviewbynode.json | 2483 +++++++++++++++++ samples/speedystore/dashboards/diskusage.json | 1254 +++++++++ .../historicalworkloadmonitoring.json | 1715 ++++++++++++ .../speedystore/dashboards/memoryusage.json | 812 ++++++ .../dashboards/pipelineperformance.json | 1508 ++++++++++ .../dashboards/pipelinesummary.json | 619 ++++ .../speedystore/dashboards/queryhistory.json | 394 +++ .../dashboards/resourcepoolmonitoring.json | 717 +++++ .../images/02_MG_202508_metrics-database.png | Bin 0 -> 73873 bytes ...ter_monitoring_hl_architecture-mfjdOm.webp | Bin 0 -> 32954 bytes .../speedystore/speedystore-datasource.yaml | 12 + 13 files changed, 12108 insertions(+) create mode 100644 samples/speedystore/README.md create mode 100644 samples/speedystore/dashboards/clusterview.json create mode 100644 samples/speedystore/dashboards/detailedclusterviewbynode.json create mode 100644 samples/speedystore/dashboards/diskusage.json create mode 100644 samples/speedystore/dashboards/historicalworkloadmonitoring.json create mode 100644 samples/speedystore/dashboards/memoryusage.json create mode 100644 samples/speedystore/dashboards/pipelineperformance.json create mode 100644 samples/speedystore/dashboards/pipelinesummary.json create mode 100644 samples/speedystore/dashboards/queryhistory.json create mode 100644 samples/speedystore/dashboards/resourcepoolmonitoring.json create mode 100644 samples/speedystore/images/02_MG_202508_metrics-database.png create mode 100644 samples/speedystore/images/cluster_monitoring_hl_architecture-mfjdOm.webp create mode 100644 samples/speedystore/speedystore-datasource.yaml diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md new file mode 100644 index 00000000..d9e72144 --- /dev/null +++ b/samples/speedystore/README.md @@ -0,0 +1,145 @@ + +# Monitoring SAS SpeedyStore (SingleStore) +## Overview +This sample demonstrates how to extend SAS Viya Monitoring for Kubernetes to monitor the SingleStore instance embedded within SAS SpeedyStore. This allows administrators to monitor their SingleStore cluster using the same Grafana instance they use to monitor the rest of their SAS Viya deployment. + +This sample is derived from the blog post Using [Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) written by Michael Goddard from SAS Education. The blog post was, in turn, based on work Michael did in preparing to cover the topic as part of the [SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) workshop available in [learn.sas.com](https://learn.sas.com/). This sample includes Grafana dashboards developed and made available by SingleStore. + +**Note: There may be other ways to achieve these same objectives, this sample documents one possible approach.** + +## Using this Sample +Enabling this monitoring will required configuring components in both SingleStore and Grafana. While we will describe how to configure the SingleStore components, you are strongly encouraged to review the official SingleStore documentation for a more comprehensive discussion of how to monitor SingleStore effectively, the options for doing so and additional implementation details. After configuring the SingleStore components, this sample covers defining the datasource within Grafana and deploying the SingleStore-specific Grafana dashboards. + +The diagram below. taken from the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/), provides a high-level overview of metric collection and reporting process. As shown, the SingleStore pipeline extracts metrics from the SingleStore cluster and stores them within a metrics database. Grafana pulls metric data directly from this metrics database to populate the dashboards administrators view. + +![Overview of SingleStore Monitoring Process ](images/cluster_monitoring_hl_architecture-mfjdOm.webp) + +### Overview of Process +* Set-up + * Set the VIYA_NS environent variable +* SingleStore + * Configure the SingleStore pipeline + * Configure metrics database + * Configure "monitoring user" +* Grafana + * Configure Grafana + * Load SingleStoer Grafana Dashboards + +### Configure the SingleStore pipeline and metrics database + +The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. We will use the `sdb-admin start-monitoring-kube` command to configure and start the monitoring. It has a number of flags to control its operations. See the SingleStore documentation for more information: [start-monitoring-kube](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/). + + +To configure and start the monitoring, including the metrics database, we will submit the following command: + +`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace {VIYA_NS} --user root --password {ROOT_PWD} --exporter-host {CLUSTER_MASTER_IP}` + +But before submitting the command, we will review the parameters being passed to the command. + +#### Set the VIYA_NS environent variable + +Since you will need to refer repeatedly to the namespace in which SAS Viya (and SingleStore) is deployed, it is helpful to define an environment variable, `VIYA_NS`,to identify the namespace and reference it in subsequent commands. + +You can use the following command to do this: + + `export VIYA_NS=myviya` + +#### The `cluster-name` parameter +The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: ***sas-singlestore-cluster***. However, it is possible to change this name, so it is important to confirm the actual cluster name before configuring the monitroing. To get the cluster name, submit the following command via the SingleStore CLI: + + `show global variables like 'cluster_name%';` + +#### The `user` and `password` parameters +A core part of the monitoring is the exporter process which collects the metric data from the cluster. The exporter process is typically run as the SingleStore 'root' user due to the permissions required. In addition, we will need the password for the SingleStore 'root' user. Note: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user is out-of-scope for this sample and we will use the 'root' user. + +You can use the following command to get the password for the 'root' user: + +`ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` + +#### The `exporter-host` parameter +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You need to provide the fully-qualified host name or IP address for the exporter host. The name needs to be resolvable by the host running the `sdb-admin` command. Since the fully-qualified host name may not be resolvable, we will use the IP address for the `exporter-host` parameter instead. + +You can obtain the IP address for the Master node by submitting the following command: + +`CLUSTER_MASTER_IP=$(kubectl -n ${NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` + +#### Accessing the Kubernetess Cluster +The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file defined in the KUBECONFIG environment variable or the ~/.kube/config file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config. + +#### Run the `sb-admin start-monitoring-kube` command +After setting all of the required parameters, submit the following command to configure and start the monitoring, including the metrics database: + +`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace {VIYA_NS} --user root --password {ROOT_PWD} --exporter-host {CLUSTER_MASTER_IP}` + +After running the command, the exporter process, the pipeline and the metrics database are created. To confirm this, you can use the SingleStore Studio. For example, in the screenshot below, you can see the newly created **'metrics'** database: +![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) + +### Configure "monitoring user" +Grafana will need to connect to the 'metrics' database and you should create a specific user to be used for that purpose. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so the user can be used to manage the metrics database, pipelines and the exporter process. + +For example, you might grant the following permissions: + +`GRANT CLUSTER, SHOW METADATA, SELECT, PROCESS ON *.* to '{S2MonitorUser}'@'%';` + +`GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to '{S2MonitorUser}'@'%';` + +Alternatively, you might GRANT the "monitoring user" minimal permissions, and create a second user ("monitoring administrator") to manage the metrics database, pipelines and the exporter process. + +|**TO DO: Where do you submit those commands? SingleStore CLI?** + +|**TO DO: Does the first GRANT statement only grant the _minimal_ permissions needed to pull metirics? And the 2nd grants the extended permissions needed to be an administrator?** + +|**TO DO: Is the user name *S2MonitorUser*?** + +### Configure Grafana Datasource +Grafana datasources provide connection information allowing Grafana to access metric information in response to user queries and to populate dashboards. + +The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the 'metrics' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update the ***url*** field in the file as well. + +Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. + +Then submit the following command to create the datasource: + +`kubectl -n $VIYA_NS create secret generic grafana-metrics-connection --from-file=$USER_DIR/monitoring/speedystore-datasource.yaml` + +After secret has been created, you need to apply a specific label to the secret to trigger the automatic provisioning (Ioading) of the datasource into Grafana. + +You can use the following command to apply the necessary label: + +`kubectl -n $VIYA_NS label secret grafana-metrics-connection "grafana_datasource=1"` + +### Import SingleStore Dashboards +To import the SingleStore dashboards into Grafana, you can use the `deploy_dashboards.sh` script found in the `monitoring/bin` sub-directory of this repository. + +You can use the following command to import all of the SingleStore dashboards: + +`./monitoring/bin/deploy_dashboards.sh samples/speedy/dashboards` + +Or, if you can import specific dashboards individually using the same script. For example, following command imports the ***Cluster View*** dashboard into Grafana: + +`./monitoring/bin/deploy_dashboards.sh samples/speedy/dashboards/clusterview.yaml` + +### Validate +Once the dashboards have been imported into Grafana, you should be all set to monitor the SingleStore instance embedded in SAS SpeedyStore. + +To validate the configuration, sign into Grafana and review each of the SingleStore dashboards you've imported. All of the imported dashboards have the ***"sas-speedystore"*** and ***"singlestore"*** tags. While the data shown will vary based on user activity, all of the dashboards should be available with no errors or warning icons or messages. + +## The Grafana Dashboards +* [Cluster View](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#cluster-view) +* [Detailed Cluster View by Node](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#detailed-cluster-view-by-node) +* [Disk Usage](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#disk-usage) +* [Historical Workload Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#historical-workload-monitoring) +* [Memory Usage](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#memory-usage) +* [Pipeline Summary](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#pipeline-summary) +* [Pipeline Performance](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#pipeline-performance) +* [Query History](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#query-history) +* [Resource Pool Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#resource-pool-monitoring) + +## Acknowledgements + +## References +[SingleStore Documentation: Configure Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/) + +[SingleStore Documentation: Detailed Discussion of each dashboard including metrics shown and when to use them](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/) + + diff --git a/samples/speedystore/dashboards/clusterview.json b/samples/speedystore/dashboards/clusterview.json new file mode 100644 index 00000000..a7f13d68 --- /dev/null +++ b/samples/speedystore/dashboards/clusterview.json @@ -0,0 +1,2449 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 261, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "", + "type": "link", + "url": "https://docs.singlestore.com/db/v8.1/en/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards.html#cluster-view-793226" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 45, + "panels": [], + "title": "Resource Utilization", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "CPU", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "max single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 20, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t1 AS (WITH t AS (\n SELECT *, lag(value) OVER w value_l, lag(time_sec) OVER w time_sec_l\n FROM\n (SELECT\n-- take the last datapoint in the interval\ntime_sec as time_sec,\nmemsql_sysinfo_cpu_used_ms/memsql_sysinfo_cpu_num_cpus value,\nhost\n FROM\n (SELECT\n max(time_sec) time_sec,\n -- this is the last counter in the time group\n max(intval) as value,\n name as metric,\n trim_host(host) host,\n $__unixEpochGroup(time_sec, $interval) as tg\n FROM metrics\n WHERE\n (cluster = '$cluster')\n and (host in ($host) or $host = '%')\n and (extractor = 'memsql')\n and (subsystem = 'sysinfo')\n and (name = 'memsql_sysinfo_cpu_used_ms' or name = 'memsql_sysinfo_cpu_num_cpus')\n and $__unixEpochFilter(time_sec)\n group by 3, 4, 5\n ) as pvt_data\n PIVOT\n (\n AVG(value)\n FOR metric\n IN ('memsql_sysinfo_cpu_used_ms', 'memsql_sysinfo_cpu_num_cpus')\n ) as pvt_table\n ) X\n WINDOW w AS (partition by host order by time_sec desc)\n)\nselect a.time_sec, (value - value_l)/(1000*(time_sec - time_sec_l)) * 100 value, a.host from t a\nWHERE time_sec_l is not null and value_l is not null\norder by 1, 2 desc, 3)\nSELECT time_sec, min(value) as `min single-core load`, avg(value) 'avg core load', max(value) as `max single-core load` from t1\ngroup by time_sec\norder by time_sec\n", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "CPU Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Memory", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Memory Usage" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select time_sec, 'Memory Usage' as metric, max(used) from (\nselect time_sec,\nhost,\nmemsql_sysinfo_mem_used_b / memsql_sysinfo_mem_total_b as used\nFROM\n(SELECT\nmax(time_sec) time_sec,\navg(value) value,\nmetric,\nhost\nFROM\n(SELECT\n time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n intval as value,\n name as metric,\n CONCAT('{', trim_host(host), '}') as host\nFROM metrics\nWHERE cluster='$cluster'\nand (host in ($host) or $host = '%')\nand extractor = 'memsql'\nand subsystem = 'sysinfo'\nand name in ('memsql_sysinfo_mem_used_b','memsql_sysinfo_mem_total_b')\nand $__unixEpochFilter(time_sec)\n) X\nGROUP BY tg, metric, host\n) as pvt_data\nPIVOT (\n AVG(value) \n FOR metric \n IN ('memsql_sysinfo_mem_used_b','memsql_sysinfo_mem_total_b')\n) as pvt_table) a\ngroup by time_sec\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Memory Utilization", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Disk Utilization", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 51, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select time_sec, 'Disk Usage' as metric, max(used) from (\nselect time_sec,\nhost,\nmemsql_sysinfo_disk_used_b / memsql_sysinfo_disk_total_b as used\nFROM\n(SELECT\nmax(time_sec) time_sec,\navg(value) value,\nmetric,\nhost\nFROM\n(SELECT\n time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n intval as value,\n name as metric,\n CONCAT('{', trim_host(host), '}') as host\nFROM metrics\nWHERE cluster='$cluster'\nand (host in ($host) or $host = '%')\nand extractor = 'memsql'\nand subsystem = 'sysinfo'\nand name in ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\nand $__unixEpochFilter(time_sec)\n) X\nGROUP BY tg, metric, host\n) as pvt_data\nPIVOT (\n AVG(value) \n FOR metric \n IN ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\n) as pvt_table) a\ngroup by time_sec\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Disk Utilization", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 44, + "panels": [], + "title": "Connections & Threads", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Number of open connections (threads_connected) to the database relative to the maximum limit (max_connections). If the utilization is near 100%, it means DB is approaching the maximum allowed connections; this can potentially lead to performance issues, as queries may need to wait in a queue until a thread becomes available to process them.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Threads - Connected", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 46, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select max(used_c / total_C) * 100 as `Threads - Connected`, \n tg as time \nfrom (SELECT time_sec as time, \n $__unixEpochGroup(time_sec, $interval) as tg, \n sum(case when name = 'memsql_variables_max_connections' then value else 0 end) as total_c,\n sum(case when name = 'memsql_status_threads_connected' then value else 0 end) as used_c,\n host, port\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n NAME in ('memsql_variables_max_connections','memsql_status_threads_connected') \n group by time, tg, host, port)\ngroup by tg\norder by tg;", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Threads - Connected", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Number of threads actively running queries (threads_running) relative to the maximum limit (max_connection_threads). If the utilization is near 100%, it suggests that the system might be reaching its capacity in terms of how many queries can be executed in parallel. This situation can lead to resource pressure, unresponsiveness, latency spikes, and even failures", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Threads - Running", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 47, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select tg as time,\n max(used_c / total_C) * 100 as 'Threads - Running:' \nfrom (SELECT time_sec as time, \n $__unixEpochGroup(time_sec, $interval) as tg, \n sum(case when name = 'memsql_variables_max_connection_threads' then value else 0 end) as total_c,\n sum(case when name = 'memsql_status_threads_running' then value else 0 end) as used_c,\n host, port\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n NAME in ('memsql_variables_max_connection_threads','memsql_status_threads_running') \n group by time, tg, host, port)\ngroup by tg\norder by tg;", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Threads - Running", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 43, + "panels": [], + "title": "Throughput", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "wps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Write queries per second" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 36, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n metric \n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n concat(name, host) as metric \n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or $host = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_%_write_queries'\n and role <> 'LEAF') subq \n GROUP BY \n metric, \n tg\n ) X WINDOW w AS (\n partition by metric \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n sum((value - value_l)/(time_sec - time_sec_l)) as 'Write queries per second'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n time_sec\norder by \n time_sec", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Write Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "wps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Rows written per second" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 34, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n max(value) as value, \n metric \n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n concat(name, host) as metric \n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or $host = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name = 'memsql_status_rows_affected_by_writes'\n and role <> 'LEAF') subq \n GROUP BY \n metric, \n tg\n ) X WINDOW w AS (\n partition by metric \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n sum((value - value_l)/(time_sec - time_sec_l)) as 'Rows written per second'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by time_sec\norder by \n 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Rows Written per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "wps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Failed write queries per second" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 41, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n metric \n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n concat(name, host) as metric \n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or $host = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_failed_write_queries'\n and role <> 'LEAF') subq \n GROUP BY \n metric, \n tg\n ) X WINDOW w AS (\n partition by metric \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n sum((value - value_l)/(time_sec - time_sec_l)) as 'Failed write queries per second'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n time_sec\norder by \n time_sec\n", + "refId": "B", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Failed Write Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Changes in the pattern of execution time per write query from the historical norm may indicate an issue with your application or changes in your workload.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 49, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time) OVER w time_l\n from (\n select max(tg) as time,\n max(value) as value,\n metric, name\n from (\n SELECT time_sec,\n $__unixEpochGroup(time_sec, $interval) as tg, \n concat(name, host) as metric,\n name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n cluster = '$cluster' AND\n (host in ($host) or $host = '%') AND\n role <> 'LEAF' AND\n name in ('memsql_status_failed_write_queries','memsql_status_successful_write_queries','memsql_status_execution_time_of_write')\n )\n group by metric, tg) X \n WINDOW w AS (partition by metric order by time))\nselect time, \n sum(case when name = 'memsql_status_execution_time_of_write' then (value - value_l) end) /\n sum(case when name in ('memsql_status_failed_write_queries','memsql_status_successful_write_queries') then (value - value_l) end) as 'Execution Time per Write Query'\nfrom t\nwhere time_l is not null \n and value_l is not null \n and value >= value_l\ngroup by time\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Execution Time per Write Query", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "rps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Read queries per second" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 33 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n metric \n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n concat(name, host) as metric \n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or $host = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_%_read_queries'\n and role <> 'LEAF') subq \n GROUP BY \n metric, \n tg\n ) X WINDOW w AS (\n partition by metric \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n sum((value - value_l)/(time_sec - time_sec_l)) as 'Read queries per second'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n time_sec\norder by \n time_sec", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Read Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "rps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Rows Read per second" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 33 + }, + "id": 35, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n max(value) as value, \n metric \n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n concat(name, host) as metric \n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or $host = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name = 'memsql_status_rows_returned_by_reads'\n and role <> 'LEAF') subq \n GROUP BY \n metric, \n tg\n ) X WINDOW w AS (\n partition by metric \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n sum((value - value_l)/(time_sec - time_sec_l)) as 'Rows Read per second'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by time_sec\norder by \n 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Rows Read per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "rps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Failed read queries per second" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 42, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n metric \n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n concat(name, host) as metric \n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or $host = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_failed_read_queries'\n and role <> 'LEAF') subq \n GROUP BY \n metric, \n tg\n ) X WINDOW w AS (\n partition by metric \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n sum((value - value_l)/(time_sec - time_sec_l)) as 'Failed read queries per second'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n time_sec\norder by \n time_sec\n", + "refId": "B", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Failed Read Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Changes in the pattern of execution time per read query from the historical norm may indicate an issue with your application or changes in your workload.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 50, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time) OVER w time_l\n from (\n select max(tg) as time,\n max(value) as value,\n metric, name\n from (\n SELECT time_sec,\n $__unixEpochGroup(time_sec, $interval) as tg, \n concat(name, host) as metric,\n name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n cluster = '$cluster' AND\n (host in ($host) or $host = '%') AND\n role <> 'LEAF' AND\n name in ('memsql_status_failed_read_queries','memsql_status_successful_read_queries','memsql_status_execution_time_of_reads')\n )\n group by metric, tg) X \n WINDOW w AS (partition by metric order by time))\nselect time, \n sum(case when name = 'memsql_status_execution_time_of_reads' then (value - value_l) end) /\n sum(case when name in ('memsql_status_failed_read_queries','memsql_status_successful_read_queries') then (value - value_l) end) as 'Execution Time per Read Query'\nfrom t\nwhere time_l is not null \n and value_l is not null \n and value >= value_l\ngroup by time\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Execution Time per Read Query", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Network Sent Bytes" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 40, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *, lag(value) OVER w value_l, lag(time_sec) OVER w time_sec_l\nFROM \n(SELECT\n max(time_sec) time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n avg(intval) as value,\n trim_metric(name, 'memsql_status_bytes_') as metric,\n trim_host(host) host,\n port\nFROM metrics\nWHERE (cluster = '$cluster')\nand (extractor = 'memsql')\nand (subsystem = 'status')\nand name in ('memsql_status_bytes_sent')\nand $__unixEpochFilter(time_sec)\nGROUP BY metric, host, port, tg\n) X\nWINDOW w AS (partition by metric, host, port order by time_sec desc)\n)\nselect time_sec, sum((value - value_l)/(time_sec - time_sec_l)) as 'Network Sent Bytes' \nfrom t a\nwhere time_sec_l is not null and value_l is not null\ngroup by time_sec\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Network Sent Bytes", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Network Received Bytes" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 39, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *, lag(value) OVER w value_l, lag(time_sec) OVER w time_sec_l\nFROM \n(SELECT\n max(time_sec) time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n avg(intval) as value,\n trim_metric(name, 'memsql_status_bytes_') as metric,\n trim_host(host) host,\n port\nFROM metrics\nWHERE (cluster = '$cluster')\nand (extractor = 'memsql')\nand (subsystem = 'status')\nand name in ('memsql_status_bytes_received')\nand $__unixEpochFilter(time_sec)\nGROUP BY metric, host, port, tg\n) X\nWINDOW w AS (partition by metric, host, port order by time_sec desc)\n)\nselect time_sec, sum((value - value_l)/(time_sec - time_sec_l)) as 'Network Received Bytes' \nfrom t a\nwhere time_sec_l is not null and value_l is not null\ngroup by time_sec\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Network Received Bytes", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "allValue": "'%'", + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from metrics where $__unixEpochFilter(time_sec)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(database_name) from act_samples where $__timeFilter(ts) and (cluster = '$cluster')", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "database_name", + "options": [], + "query": "select distinct(database_name) from act_samples where $__timeFilter(ts) and (cluster = '$cluster')", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "host", + "options": [], + "query": "select distinct(host) from metrics where host is not NULL and $__unixEpochFilter(time_sec) and (cluster='$cluster')", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "auto": true, + "auto_count": 50, + "auto_min": "1m", + "current": { + "text": "$__auto", + "value": "$__auto" + }, + "name": "interval", + "options": [ + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Cluster View", + "uid": "detailed-cluster-view2", + "version": 1 +} diff --git a/samples/speedystore/dashboards/detailedclusterviewbynode.json b/samples/speedystore/dashboards/detailedclusterviewbynode.json new file mode 100644 index 00000000..6e0ddf05 --- /dev/null +++ b/samples/speedystore/dashboards/detailedclusterviewbynode.json @@ -0,0 +1,2483 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 262, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "", + "type": "link", + "url": "https://docs.singlestore.com/db/v8.1/en/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards.html#cluster-view-793226" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 47, + "panels": [], + "title": "Resource Utilization", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "CPU", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "max single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 20, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t1 AS (WITH t AS (\n SELECT *, lag(value) OVER w value_l, lag(time_sec) OVER w time_sec_l\n FROM\n (SELECT\n-- take the last datapoint in the interval\ntime_sec as time_sec,\nmemsql_sysinfo_cpu_used_ms/memsql_sysinfo_cpu_num_cpus value,\nhost\n FROM\n (SELECT\n max(time_sec) time_sec,\n -- this is the last counter in the time group\n max(intval) as value,\n name as metric,\n trim_host(host) host,\n $__unixEpochGroup(time_sec, $interval) as tg\n FROM metrics\n WHERE\n (cluster = '$cluster')\n and (host in ($host) or concat($host) = '%')\n and (extractor = 'memsql')\n and (subsystem = 'sysinfo')\n and (name = 'memsql_sysinfo_cpu_used_ms' or name = 'memsql_sysinfo_cpu_num_cpus')\n and $__unixEpochFilter(time_sec)\n group by metric, host, tg\n ) as pvt_data\n PIVOT\n (\n AVG(value)\n FOR metric\n IN ('memsql_sysinfo_cpu_used_ms', 'memsql_sysinfo_cpu_num_cpus')\n ) as pvt_table\n ) X\n WINDOW w AS (partition by host order by time_sec desc)\n)\nselect a.time_sec, (value - value_l)/(1000*(time_sec - time_sec_l)) * 100 value, a.host from t a\nWHERE time_sec_l is not null and value_l is not null\norder by 1, 2 desc, 3)\nSELECT time_sec, host, max(value) 'CPU:' from t1\ngroup by time_sec, host\norder by time_sec, host\n", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "CPU Utilization per Host", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Memory", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select * from (\nselect time_sec,\nhost,\nmemsql_sysinfo_mem_used_b / memsql_sysinfo_mem_total_b as 'Memory:'\nFROM\n(SELECT\n max(time_sec) time_sec,\n avg(value) value,\n metric,\n host\n FROM\n (SELECT\n time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n intval as value,\n name as metric,\n trim_host(host) as host\n FROM metrics\n WHERE cluster='$cluster'\n and (host in ($host) or concat($host) = '%')\n and extractor = 'memsql'\n and subsystem = 'sysinfo'\n and name in ('memsql_sysinfo_mem_used_b','memsql_sysinfo_mem_total_b')\n and $__unixEpochFilter(time_sec)\n ) X\n GROUP BY tg, metric, host\n) as pvt_data\nPIVOT (\n AVG(value) \n FOR metric \n IN ('memsql_sysinfo_mem_used_b','memsql_sysinfo_mem_total_b')\n) as pvt_table) a\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Memory Utilization per Host", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Disk Utilization", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 58, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select * from (\nselect time_sec,\nhost,\nmemsql_sysinfo_disk_used_b / memsql_sysinfo_disk_total_b as 'Disk:'\nFROM\n(SELECT\n max(time_sec) time_sec,\n avg(value) value,\n metric,\n host\n FROM\n (SELECT\n time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n intval as value,\n name as metric,\n trim_host(host) as host\n FROM metrics\n WHERE cluster='$cluster'\n and (host in ($host) or concat($host) = '%')\n and extractor = 'memsql'\n and subsystem = 'sysinfo'\n and name in ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\n and $__unixEpochFilter(time_sec)\n ) X\n GROUP BY tg, metric, host\n) as pvt_data\nPIVOT (\n AVG(value) \n FOR metric \n IN ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\n) as pvt_table) a\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Disk Utilization per Host", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 46, + "panels": [], + "title": "Connections & Threads", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Number of open connections (threads_connected) to the database relative to the maximum limit (max_connections). If the utilization is near 100%, it means DB is approaching the maximum allowed connections; this can potentially lead to performance issues, as queries may need to wait in a queue until a thread becomes available to process them.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Threads - Connected", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "max single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 55, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select tg as time,\n concat(host,':',port,' {',role,'}') as node,\n max(used_c / total_C) * 100 as 'Threads - Connected:'\nfrom (SELECT time_sec as time, \n $__unixEpochGroup(time_sec, $interval) as tg, \n sum(case when name = 'memsql_variables_max_connections' then value else 0 end) as total_c,\n sum(case when name = 'memsql_status_threads_connected' then value else 0 end) as used_c,\n host, port, role\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n (host in ($host) or concat($host) = '%') AND\n (port in ($port) or concat($port) = '%') AND\n NAME in ('memsql_variables_max_connections','memsql_status_threads_connected') \n group by time, tg, host, port, role)\ngroup by tg, node\norder by tg, node;", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Threads - Connected", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Number of threads actively running queries (threads_running) relative to the maximum limit (max_connection_threads). If the utilization is near 100%, it suggests that the system might be reaching its capacity in terms of how many queries can be executed in parallel. This situation can lead to resource pressure, unresponsiveness, latency spikes, and even failures", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Threads - Running", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "max single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min single-core load" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 56, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select tg as time,\n concat(host,':',port,' {',role,'}') as node,\n max(used_c / total_C) * 100 as 'Threads - Running:' \nfrom (SELECT time_sec as time, \n $__unixEpochGroup(time_sec, $interval) as tg, \n sum(case when name = 'memsql_variables_max_connection_threads' then value else 0 end) as total_c,\n sum(case when name = 'memsql_status_threads_running' then value else 0 end) as used_c,\n host, port, role\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n (host in ($host) or concat($host) = '%') AND\n (port in ($port) or concat($port) = '%') AND\n NAME in ('memsql_variables_max_connection_threads','memsql_status_threads_running') \n group by time, tg, host, port, role)\ngroup by tg, node\norder by tg, node;", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Threads - Running", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 45, + "panels": [], + "title": "Throughput", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "wps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 36, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n host , port, name, role\n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n host , port, name, role\n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or concat($host) = '%')\n and (port in ($port) or concat($port) = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_%_write_queries'\n and role <> 'LEAF') subq \n GROUP BY \n host, port, name, role,\n tg\n ) X WINDOW w AS (\n partition by host, port , name\n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n concat(host,':',port,' {',role,'}') as node,\n sum((value - value_l)/(time_sec - time_sec_l)) as 'Write queries per second:'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n 1,2\norder by \n 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Write Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "wps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 34, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n max(value) as value, \n host, port, role\n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n host, port , role\n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or concat($host) = '%')\n and (port in ($port) or concat($port) = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name = 'memsql_status_rows_affected_by_writes'\n and role <> 'LEAF') subq \n GROUP BY \n host, port, role,\n tg\n ) X WINDOW w AS (\n partition by host, port \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n concat(host,':',port,' {',role,'}') as node,\n sum((value - value_l)/(time_sec - time_sec_l)) as 'Rows written per second:'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by 1,2\norder by \n 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Rows Written per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "wps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 43, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n host , port, role\n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n host , port, role\n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or concat($host) = '%')\n and (port in ($port) or concat($port) = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_failed_write_queries'\n and role <> 'LEAF') subq \n GROUP BY \n host, port, role,\n tg\n ) X WINDOW w AS (\n partition by host, port \n order by \n time_sec\n )\n) \nSELECT \n time_sec, \n concat(host,':',port,' {',role,'}') as node,\n sum((value - value_l)/(time_sec - time_sec_l)) as 'Failed Write queries per second:'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n 1,2\norder by \n 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Failed Write Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Changes in the pattern of execution time per write query from the historical norm may indicate an issue with your application or changes in your workload.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 53, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time) OVER w time_l\n from (\n select max(tg) as time,\n max(value) as value,\n host,port, name, role\n from (\n SELECT time_sec,\n $__unixEpochGroup(time_sec, $interval) as tg, \n host,\n port,role,\n name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n cluster = '$cluster' AND\n (host in ($host) or concat($host) = '%') AND\n (port in ($port) or concat($port) = '%') AND\n role <> 'LEAF' AND\n name in ('memsql_status_failed_write_queries','memsql_status_successful_write_queries','memsql_status_execution_time_of_write')\n )\n group by name, host, port, role, tg) X \n WINDOW w AS (partition by host,port,name order by time))\nselect time, \n concat(host,':',port,' {',role,'}') as node,\n sum(case when name = 'memsql_status_execution_time_of_write' then (value - value_l) end) /\n sum(case when name in ('memsql_status_failed_write_queries','memsql_status_successful_write_queries') then (value - value_l) end) as 'Execution Time per Write Query:'\nfrom t\nwhere time_l is not null \n and value_l is not null \n and value >= value_l\ngroup by time, node\norder by time, node", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Execution Time per Write Query", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "rps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n host , port, name, role\n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n host , port, name, role\n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or concat($host) = '%')\n and (port in ($port) or concat($port) = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_%_read_queries'\n and role <> 'LEAF') subq \n GROUP BY \n host, port, name, role,\n tg\n ) X WINDOW w AS (\n partition by host, port , name\n order by \n time_sec\n )\n) \nSELECT \n time_sec, concat(host,':',port,' {',role,'}') as node,\n sum((value - value_l)/(time_sec - time_sec_l)) as 'Read queries per second:'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n 1,2\norder by \n 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Read Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "rps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 35, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT\n *,\n lag(value) OVER w value_l,\n lag(time_sec) OVER w time_sec_l\n FROM\n (\n SELECT\n max(time_sec) as time_sec,\n max(value) as value, \n host, port, role\n FROM\n (\n SELECT\n time_sec,\n $__unixEpochGroup(time_sec, $interval) as tg,\n intval as value,\n host, port, role\n FROM\n `metrics`\n WHERE\n $__unixEpochFilter(time_sec)\n and (cluster = '$cluster')\n and (host in ($host) or concat($host) = '%')\n and (port in ($port) or concat($port) = '%')\n and extractor = 'memsql'\n and subsystem = 'status'\n and name = 'memsql_status_rows_returned_by_reads'\n and role <> 'LEAF') subq\n GROUP BY\n host, port, role,\n tg\n ) X WINDOW w AS (\n partition by host, port\n order by\n time_sec\n )\n)\nSELECT\n time_sec,\n concat(host,':',port,' {',role,'}') as node,\n sum((value - value_l)/(time_sec - time_sec_l)) as 'Rows Read per second:'\nFROM\n t a\nwhere\n time_sec_l is not null\n and value_l is not null\n and value >= value_l\ngroup by 1,2\norder by\n 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Rows Read per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "rps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 44, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time_sec) OVER w time_sec_l \n FROM \n (\n SELECT \n max(time_sec) as time_sec, \n avg(value) as value, \n host , port, role\n FROM \n (\n SELECT \n time_sec, \n $__unixEpochGroup(time_sec, $interval) as tg, \n intval as value, \n host , port, role\n FROM \n `metrics` \n WHERE \n $__unixEpochFilter(time_sec) \n and (cluster = '$cluster') \n and (host in ($host) or concat($host) = '%')\n and (port in ($port) or concat($port) = '%')\n and extractor = 'memsql' \n and subsystem = 'status' \n and name like 'memsql_status_failed_read_queries'\n and role <> 'LEAF') subq \n GROUP BY \n host, port, role,\n tg\n ) X WINDOW w AS (\n partition by host, port \n order by \n time_sec\n )\n) \nSELECT \n time_sec, concat(host,':',port,' {',role,'}') as node,\n sum((value - value_l)/(time_sec - time_sec_l)) as 'Failed Read queries per second:'\nFROM \n t a \nwhere \n time_sec_l is not null \n and value_l is not null \n and value >= value_l \ngroup by\n 1,2\norder by \n 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Failed Read Queries per Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Changes in the pattern of execution time per read query from the historical norm may indicate an issue with your application or changes in your workload.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 43 + }, + "id": 54, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l, \n lag(time) OVER w time_l\n from (\n select max(tg) as time,\n max(value) as value,\n host,port, name, role\n from (\n SELECT time_sec,\n $__unixEpochGroup(time_sec, $interval) as tg, \n host,\n port, role,\n name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n cluster = '$cluster' AND\n (host in ($host) or concat($host) = '%') AND\n (port in ($port) or concat($port) = '%') AND\n role <> 'LEAF' AND\n name in ('memsql_status_failed_read_queries','memsql_status_successful_read_queries','memsql_status_execution_time_of_reads')\n )\n group by name, host, port,role, tg) X \n WINDOW w AS (partition by host,port,name order by time))\nselect time, \n concat(host,':',port,' {',role,'}') as node,\n sum(case when name = 'memsql_status_execution_time_of_reads' then (value - value_l) end) /\n sum(case when name in ('memsql_status_failed_read_queries','memsql_status_successful_read_queries') then (value - value_l) end) as 'Execution Time per read Query:'\nfrom t\nwhere time_l is not null \n and value_l is not null \n and value >= value_l\ngroup by time, node\norder by time, node", + "refId": "A", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Execution Time per Read Query", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 51 + }, + "id": 39, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *, lag(value) OVER w value_l, lag(time_sec) OVER w time_sec_l\nFROM \n(SELECT\n max(time_sec) time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n avg(intval) as value,\n trim_metric(name, 'memsql_status_bytes_') as metric,\n trim_host(host) host,\n port, role\nFROM metrics\nWHERE (cluster = '$cluster')\nand (extractor = 'memsql')\nand (subsystem = 'status')\nand name in ('memsql_status_bytes_received')\nand (host in ($host) or concat($host) = '%')\nand (port in ($port) or concat($port) = '%')\nand $__unixEpochFilter(time_sec)\nGROUP BY metric, host, port, role, tg\n) X\nWINDOW w AS (partition by metric, host, port order by time_sec desc)\n)\nselect time_sec, concat(host,':',port,' {',role,'}') as node, sum((value - value_l)/(time_sec - time_sec_l)) 'Network Received bytes:'\nfrom t a\nwhere time_sec_l is not null and value_l is not null\ngroup by 1,2\norder by 1,2", + "refId": "B", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Network Received Bytes", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 51 + }, + "id": 40, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "9.3.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *, lag(value) OVER w value_l, lag(time_sec) OVER w time_sec_l\nFROM \n(SELECT\n max(time_sec) time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n avg(intval) as value,\n trim_metric(name, 'memsql_status_bytes_') as metric,\n trim_host(host) host,\n port, role\nFROM metrics\nWHERE (cluster = '$cluster')\nand (extractor = 'memsql')\nand (subsystem = 'status')\nand name in ('memsql_status_bytes_sent')\nand (host in ($host) or concat($host) = '%')\nand (port in ($port) or concat($port) = '%')\nand $__unixEpochFilter(time_sec)\nGROUP BY metric, host, port, role, tg\n) X\nWINDOW w AS (partition by metric, host, port order by time_sec desc)\n)\nselect time_sec, concat(host,':',port,' {',role,'}') as node, sum((value - value_l)/(time_sec - time_sec_l)) 'Network Sent bytes:' \nfrom t a\nwhere time_sec_l is not null and value_l is not null\ngroup by 1,2\norder by 1,2", + "refId": "B", + "select": [ + [ + { + "params": [ + "CPU_TIME_MS" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Network Sent Bytes", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "allValue": "'%'", + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from metrics where $__unixEpochFilter(time_sec)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(database_name) from act_samples where $__timeFilter(ts) and (cluster = '$cluster')", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "database_name", + "options": [], + "query": "select distinct(database_name) from act_samples where $__timeFilter(ts) and (cluster = '$cluster')", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": true, + "multi": true, + "name": "host", + "options": [], + "query": "select distinct(host) from metrics where host is not NULL and $__unixEpochFilter(time_sec) and (cluster='$cluster')", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(port) from metrics where host is not NULL and $__unixEpochFilter(time_sec) and (cluster='$cluster') and (host in ($host) or concat($host) = '%') and port is not null", + "includeAll": true, + "multi": true, + "name": "port", + "options": [], + "query": "select distinct(port) from metrics where host is not NULL and $__unixEpochFilter(time_sec) and (cluster='$cluster') and (host in ($host) or concat($host) = '%') and port is not null", + "refresh": 1, + "regex": "", + "sort": 3, + "type": "query" + }, + { + "auto": true, + "auto_count": 50, + "auto_min": "1m", + "current": { + "text": "$__auto", + "value": "$__auto" + }, + "name": "interval", + "options": [ + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Detailed Cluster View By Node", + "uid": "TVggJLbVk", + "version": 1 +} diff --git a/samples/speedystore/dashboards/diskusage.json b/samples/speedystore/dashboards/diskusage.json new file mode 100644 index 00000000..84f076ee --- /dev/null +++ b/samples/speedystore/dashboards/diskusage.json @@ -0,0 +1,1254 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 263, + "links": [], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Disk Utilization", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 13, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select * from (\nselect time_sec,\nhost,\nmemsql_sysinfo_disk_used_b / memsql_sysinfo_disk_total_b as 'Disk:'\nFROM\n(SELECT\n max(time_sec) time_sec,\n avg(value) value,\n metric,\n host\n FROM\n (SELECT\n time_sec,\n $__unixEpochGroup(time_sec,$interval) tg,\n intval as value,\n name as metric,\n trim_host(host) as host\n FROM metrics\n WHERE cluster='$cluster'\n and (host in ('$host') or concat('$host') = '%')\n and extractor = 'memsql'\n and subsystem = 'sysinfo'\n and name in ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\n and $__unixEpochFilter(time_sec)\n ) X\n GROUP BY tg, metric, host\n) as pvt_data\nPIVOT (\n AVG(value) \n FOR metric \n IN ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\n) as pvt_table) a\norder by time_sec", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Disk Utilization per Host", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total Disk Size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.fillOpacity", + "value": 30 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 14, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select sum(used_c) as 'Total Used',\n sum(total_c) as 'Total Disk Size', \n tg as time\nfrom (SELECT $__unixEpochGroup(time_sec, $interval) as tg,\n max(case when name = 'memsql_sysinfo_disk_total_b' then value else 0 end) as total_c,\n max(case when name = 'memsql_sysinfo_disk_used_b' then value else 0 end) as used_c,\n host\n FROM metrics\n WHERE cluster='$cluster'\n and (host in ('$host') or concat('$host') = '%')\n and extractor = 'memsql'\n and subsystem = 'sysinfo'\n and name in ('memsql_sysinfo_disk_used_b','memsql_sysinfo_disk_total_b')\n and $__unixEpochFilter(time_sec)\n group by tg, host)\nwhere used_c > 0 & total_c > 0\ngroup by tg\norder by tg;", + "refId": "B", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select tg as time,\n sum(memsql_disk_usage_tracelogs_b) tracelogs,\n sum(memsql_disk_usage_plancache_b) plancache,\n sum(memsql_disk_usage_auditlogs_b) auditlogs,\n sum(memsql_disk_usage_user_data_b + memsql_disk_usage_other_data_b) data\nfrom \n (\n SELECT $__unixEpochGroup(time_sec, $interval) AS tg, \n max(case when name = 'memsql_disk_usage_tracelogs_b' then value else 0 end) as memsql_disk_usage_tracelogs_b,\n max(case when name = 'memsql_disk_usage_plancache_b' then value else 0 end) as memsql_disk_usage_plancache_b,\n max(case when name = 'memsql_disk_usage_auditlogs_b' then value else 0 end) as memsql_disk_usage_auditlogs_b,\n max(case when name = 'memsql_disk_usage_other_data_b' then value else 0 end) as memsql_disk_usage_other_data_b,\n max(case when name = 'memsql_disk_usage_user_data_b' then value else 0 end) as memsql_disk_usage_user_data_b,\n host AS host\n FROM metrics\n WHERE cluster='$cluster'\n and (host in ('$host') or concat('$host') = '%')\n and $__unixEpochFilter(time_sec)\n and NAME in ('memsql_disk_usage_tracelogs_b','memsql_disk_usage_plancache_b', 'memsql_disk_usage_auditlogs_b', 'memsql_disk_usage_other_data_b', 'memsql_disk_usage_user_data_b')\n group by tg, host\n ) as used\ngroup by \n time \norder by \n time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Distribution of Components using Disk", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Breaksdown consumption of disk by \"Data\" category (in the left graph), adding utilization across all components will be equal to disk utilized by \"Data\"", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total Available Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Cache Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.fillOpacity", + "value": 30 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 15, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select tg as time,\n sum(memsql_data_disk_usage_tempblobs_b) 'data/tempblobs',\n sum(memsql_data_disk_usage_snapshots_b) 'data/snapshots',\n sum(memsql_data_disk_usage_blobs_b) 'data/blobs',\n sum(memsql_data_disk_usage_logs_b) 'data/transaction logs',\n sum(memsql_data_disk_usage_other_b + memsql_disk_usage_other_data_b) 'data/other'\nfrom \n (\n SELECT $__unixEpochGroup(time_sec, $interval) AS tg, \n labels::$database_name as db,\n host AS host, \n max(case when name = 'memsql_data_disk_usage_tempblobs_b' then value else 0 end) as memsql_data_disk_usage_tempblobs_b,\n max(case when name = 'memsql_data_disk_usage_snapshots_b' then value else 0 end) as memsql_data_disk_usage_snapshots_b,\n max(case when name = 'memsql_data_disk_usage_blobs_b' then value else 0 end) as memsql_data_disk_usage_blobs_b,\n max(case when name = 'memsql_data_disk_usage_logs_b' then value else 0 end) as memsql_data_disk_usage_logs_b,\n max(case when name = 'memsql_data_disk_usage_other_b' then value else 0 end) as memsql_data_disk_usage_other_b,\n max(case when name = 'memsql_disk_usage_other_data_b' then value else 0 end) as memsql_disk_usage_other_data_b\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n cluster='$cluster' and \n (host in ('$host') or concat('$host') = '%') and\n NAME in ('memsql_disk_usage_other_data_b','memsql_data_disk_usage_tempblobs_b','memsql_data_disk_usage_snapshots_b', 'memsql_data_disk_usage_blobs_b', 'memsql_data_disk_usage_logs_b', 'memsql_data_disk_usage_other_b')\n group by 1,2,3\n ) as used\ngroup by \n time \norder by \n time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Breakdown of Disk Utilization by Data", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Breaksdown consumption of disk by databases, adding utilization across all databases will be equal to disk utilized by \"Data\"", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total Available Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Cache Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.fillOpacity", + "value": 30 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 16, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select tg as time,\n db,\n sum(value) as ' '\nfrom (\n SELECT $__unixEpochGroup(time_sec, $interval) AS tg,\n name,\n labels::$database_name as db,\n host AS host, \n max(value) as value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) and\n cluster='$cluster' and \n (host in ('$host') or concat('$host') = '%') and\n value > 0 and\n name in ('memsql_data_disk_usage_tempblobs_b','memsql_data_disk_usage_snapshots_b', 'memsql_data_disk_usage_blobs_b', 'memsql_data_disk_usage_logs_b', 'memsql_data_disk_usage_other_b')\n GROUP by 1,2,3,4\n ) as pvt_data\ngroup by 1,2\norder by 1,2", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Distribution of Databases using Disk", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "It provides insights into the performance of your SingleStoreDB's blob cache activity. By understanding and monitoring the rate at which the blob cache is downloading files from remote storage, you can identify potential performance bottlenecks or issues related to blob cache activity. \nFor instance: if you observe high download rates given the size of your database and scale of your hardware, you might consider increasing the local cache size.\nBy keeping an eye on this metric, you can make well-informed decisions regarding your cluster's performance and resource allocation to ensure optimal system operation.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "MiBs" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total Available Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Cache Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.fillOpacity", + "value": 30 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 17, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select tg as time,\n db,\n sum(value) as ' '\n from (\n SELECT $__unixEpochGroup(time_sec, $interval) AS tg,\n name,\n labels::$database_name as db,\n host AS host, \n max(value) as value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) and\n cluster='$cluster' and\n (host in ('$host') or concat('$host') = '%') and\n name in ('memsql_bottomless_status_blob_cache_download_mb_per_sec')\n GROUP by 1,2,3,4\n ) as pvt_data\ngroup by 1,2\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Blob Cache Downloaded per Second (by database)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "It provides insights into the performance of your SingleStoreDB's blob cache activity. By tracking this metric, you can optimize system resource utilization based on your data management needs. If evictions occur at a high rate, it may indicate that the cache size is too small or that the workload is causing a lot of cache turnover. In such cases, you can take appropriate measures, such as adjusting cache size or reviewing data access patterns, to improve overall cluster performance.\nMonitoring this metric, helps you identify potential performance bottlenecks related to the blob cache and make well-informed decisions for optimizing your SingleStore cluster's performance.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "MiBs" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total Available Cache" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Cache Used" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.fillOpacity", + "value": 30 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 18, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select tg as time,\n db,\n sum(value) as ' '\n from (\n SELECT $__unixEpochGroup(time_sec, $interval) AS tg,\n name,\n labels::$database_name as db,\n host AS host, \n max(value) as value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) and\n cluster='$cluster' and\n (host in ('$host') or concat('$host') = '%') and\n name in ('memsql_bottomless_status_blob_cache_eviction_mb_per_sec')\n GROUP by 1,2,3,4\n ) as pvt_data\ngroup by 1,2\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Blob Cache Evicted per Second (by database)", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from metrics where $__unixEpochFilter(time_sec)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "127.0.0.1", + "value": "127.0.0.1" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(host) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and host is not NULL and host != \"\"", + "includeAll": false, + "name": "host", + "options": [], + "query": "select distinct(host) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and host is not NULL and host != \"\"", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "3307", + "value": "3307" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "hide": 2, + "includeAll": false, + "name": "port", + "options": [], + "query": "select distinct(port) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and port is not NULL", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "auto": true, + "auto_count": 50, + "auto_min": "1m", + "current": { + "text": "1m", + "value": "1m" + }, + "name": "interval", + "options": [ + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [] + }, + "timezone": "", + "title": "Disk Usage", + "uid": "ccd894b4-7e3b-43e0-966b-579ac7eb3714", + "version": 1 +} diff --git a/samples/speedystore/dashboards/historicalworkloadmonitoring.json b/samples/speedystore/dashboards/historicalworkloadmonitoring.json new file mode 100644 index 00000000..bad3c679 --- /dev/null +++ b/samples/speedystore/dashboards/historicalworkloadmonitoring.json @@ -0,0 +1,1715 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 264, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 22, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l,\n lag(elp) OVER w elp_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n ifnull(aggregator_activity_name, activity_name) agg_name,\n database_name db,\n sum(elapsed_time_ms) as elp,\n sum(IFNULL(memory_major_faults,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_type = 'Query')\n and ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') OR activity_name = '$hidden_activity_name')\n and activity_name = agg_name\n group by 1,2,3,4,5\n ) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(ts,$interval) time_sec,\n a.db,\n sum(a.elp - a.elp_l)/sum(a.total- a.total_l) ' '\nfrom t a\nwhere a.total >a.total_l and\n a.elp >a.elp_l\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Elapsed Time per Execution by Database", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Number of query executions", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Query Execution Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 21, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min", + "sum" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n ifnull(aggregator_activity_name, activity_name) agg_name,\n database_name db,\n sum(IFNULL(memory_major_faults,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_type = 'Query')\n and ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') OR activity_name = '$hidden_activity_name')\n and activity_name = agg_name\n group by 1,2,3,4,5\n ) q\nWINDOW w AS(partition by cluster, db, name order by ts))\nselect $__timeGroup(ts,$interval) time_sec,\n sum(a.total- a.total_l) execution_count\nfrom t a\nwhere a.total>a.total_l\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Execution Count", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 19, + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Time spent running on all the CPUs across the workspace reported by database", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "CPU time (core ms)", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 0, + "y": 10 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l,\n lag(cpu) OVER w cpu_l\nFROM (\n select ts,\n cluster,\n ifnull(act.aggregator_activity_name, act.activity_name) name,\n database_name db,\n sum(cpu_time_ms) as cpu,\n sum(if(activity_name = name, IFNULL(memory_major_faults,0), 0) +\n if(activity_name = name, IFNULL(success_count,0), 0) +\n if(activity_name = name, IFNULL(failure_count,0), 0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_type = 'Query')\n and ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') OR name = '$hidden_activity_name')\n group by 1,2,3,4\n ) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(ts,$interval) time_sec,\n a.db,\n sum(a.cpu - a.cpu_l)/sum(a.total- a.total_l) ' '\nfrom t a\nwhere a.total > 0 and\n a.total >a.total_l and\n a.cpu >a.cpu_l\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "CPU Time per Execution by Database", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 6, + "y": 10 + }, + "id": 14, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(elp) OVER w elp_l,\n lag(memory_bs) OVER w memory_bs_l\nFROM (\n select ts,\n cluster,\n ifnull(act.aggregator_activity_name, act.activity_name) name,\n database_name db,\n sum(if(activity_name = name, elapsed_time_ms,0)) as elp,\n sum(memory_bs) as memory_bs\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_type = 'Query')\n and ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') OR name = '$hidden_activity_name')\n group by 1,2,3,4\n ) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(ts,$interval) time_sec,\n a.db,\n sum(1000*(a.memory_bs - a.memory_bs_l))/sum(a.elp- a.elp_l) ' '\nfrom t a\nwhere a.elp > 0 and\n a.memory_bs >a.memory_bs_l and\n a.elp >a.elp_l\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Memory Bytes per Execution by Database", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 12, + "y": 10 + }, + "id": 23, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l,\n lag(disk_b) OVER w disk_b_l\nFROM (\n select ts,\n cluster,\n ifnull(act.aggregator_activity_name, act.activity_name) name,\n database_name db,\n sum(disk_b) as disk_b,\n sum(if(activity_name = name, IFNULL(memory_major_faults,0), 0) +\n if(activity_name = name, IFNULL(success_count,0), 0) +\n if(activity_name = name, IFNULL(failure_count,0), 0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_type = 'Query')\n and ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') OR name = '$hidden_activity_name')\n group by 1,2,3,4\n ) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(ts,$interval) time_sec,\n a.db,\n sum(a.disk_b - a.disk_b_l)/sum(a.total- a.total_l) ' '\nfrom t a\nwhere a.total > 0 and\n a.total >a.total_l and\n a.disk_b >a.disk_b_l\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Disk Bytes per Execution by Database", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 6, + "x": 18, + "y": 10 + }, + "id": 17, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l,\n lag(network_b) OVER w network_b_l\nFROM (\n select ts,\n cluster,\n ifnull(act.aggregator_activity_name, act.activity_name) name,\n database_name db,\n sum(network_b) as network_b,\n sum(if(activity_name = name, IFNULL(memory_major_faults,0), 0) +\n if(activity_name = name, IFNULL(success_count,0), 0) +\n if(activity_name = name, IFNULL(failure_count,0), 0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_type = 'Query')\n and ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') OR name = '$hidden_activity_name')\n group by 1,2,3,4\n ) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(ts,$interval) time_sec,\n a.db,\n sum(a.network_b - a.network_b_l)/sum(a.total- a.total_l) ' '\nfrom t a\nwhere a.total > 0 and\n a.total >a.total_l and\n a.network_b >a.network_b_l\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Network Bytes per Execution by Database", + "type": "timeseries" + } + ], + "title": "Resource Usage", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 20, + "panels": [], + "title": "Metrics by Query Plan", + "type": "row" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Elapsed Time - Wall clock milliseconds elapsed during execution; CPU Time - Milliseconds spent running on all the CPUs across the workspace. This is likely to exceed the observed elapsed time because the tasks are likely to have executed concurrently", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [ + { + "options": { + "total_time": { + "index": 0, + "text": "Total Elapsed Time" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 50 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "uniq_act" + }, + "properties": [ + { + "id": "custom.hidden", + "value": false + }, + { + "id": "custom.inspect", + "value": true + }, + { + "id": "custom.filterable", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "type" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/Time/" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query_plan" + }, + "properties": [ + { + "id": "custom.width", + "value": 545 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "/d/1xNFf_iSk/historical-workload-monitoring?var-cluster=[[cluster]]&var-hidden_activity_name=${__data.fields.uniq_act}&${__url_time_range}" + } + ] + }, + { + "id": "custom.inspect", + "value": true + }, + { + "id": "custom.filterable", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Failure Rate" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.width", + "value": 98 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total Elapsed Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 149 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Elapsed Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 145 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Execution Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 130 + }, + { + "id": "unit", + "value": "short" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Failure Count" + }, + "properties": [ + { + "id": "custom.width", + "value": 106 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "db" + }, + "properties": [ + { + "id": "custom.width", + "value": 151 + }, + { + "id": "custom.filterable", + "value": true + }, + { + "id": "custom.inspect", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Query_plan_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 158 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/Bytes/" + }, + "properties": [ + { + "id": "unit", + "value": "bytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Disk Bytes" + }, + "properties": [ + { + "id": "custom.width", + "value": 127 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total CPU Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 124 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. CPU Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 119 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Disk Read Bytes (logical)" + }, + "properties": [ + { + "id": "custom.width", + "value": 224 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Disk Write Bytes (logical)" + }, + "properties": [ + { + "id": "custom.width", + "value": 225 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Network Recieved Bytes (logical)" + }, + "properties": [ + { + "id": "custom.width", + "value": 281 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Network Send Bytes (logical)" + }, + "properties": [ + { + "id": "custom.width", + "value": 252 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg. Network Received Bytes (logical)" + }, + "properties": [ + { + "id": "custom.width", + "value": 275 + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select res.*, q.query_text as query_plan from ( \nWITH t AS (\n\nSELECT *,\nlag(cpu) OVER w cpu_l,\nlag(disk_b) OVER w disk_b_l,\nlag(disk_logical_read_b) OVER w disk_logical_read_b_l,\nlag(disk_logical_write_b) OVER w disk_logical_write_b_l,\nlag(network_b) OVER w network_b_l,\nlag(network_logical_recv_b) OVER w network_logical_recv_b_l,\nlag(network_logical_send_b) OVER w network_logical_send_b_l,\nlag(memory_bs) OVER w memory_bs_l,\nlag(elp) OVER w elp_l,\nlag(fail) OVER w fail_l,\nlag(total) OVER w total_l\nFROM\n(\nselect\nact.cluster,\nact.ts,\nifnull(database_name,'-') db,\nifnull(act.aggregator_activity_name, act.activity_name) uniq_act,\nsum(cpu_time_ms) cpu,\nsum(disk_b) disk_b,\nsum(disk_logical_read_b) disk_logical_read_b,\nsum(disk_logical_write_b) disk_logical_write_b,\nsum(network_b) network_b,\nsum(network_logical_recv_b) network_logical_recv_b,\nsum(network_logical_send_b) network_logical_send_b,\nsum(memory_bs) memory_bs,\nsum(if (activity_name = uniq_act, elapsed_time_ms, 0)) elp,\nsum(if(activity_name = uniq_act, IFNULL(failure_count,0), 0)) fail,\nsum(if(activity_name = uniq_act, IFNULL(memory_major_faults,0), 0) +\n if(activity_name = uniq_act, IFNULL(success_count,0), 0) +\n if(activity_name = uniq_act, IFNULL(failure_count,0), 0)) total\nfrom `act_samples` act\nwhere $__timeFilter(act.ts)\nand (cluster = '$cluster')\nand (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\nand ('All' in ('$hidden_activity_name') OR 'Select a query in the table below' in ('$hidden_activity_name') \n OR (uniq_act in ('$hidden_activity_name'))\n )\nand (act.activity_type = 'Query')\ngroup by 1,2,3,4\n) q\nWINDOW w AS(partition by cluster, db, uniq_act order by ts) \n)\nselect \ndb, \nelp as 'Total Elapsed Time', \nelp/total 'Avg. Elapsed Time', \ncpu as 'Total CPU Time', \ncpu/total as 'Avg. CPU Time',\ndisk_b/total as 'Avg. Disk Bytes',\ndisk_logical_read_b/total as 'Avg. Disk Read Bytes (logical)',\ndisk_logical_write_b/total as 'Avg. Disk Write Bytes (logical)',\nnetwork_logical_recv_b/total as 'Avg. Network Received Bytes (logical)',\nnetwork_logical_send_b/total as 'Avg. Network Send Bytes (logical)',\nnetwork_b/total as 'Avg. Network Bytes',\n(1000*memory_bs)/elp as 'Avg. Memory Bytes',\ntotal as 'Execution Count', \nfail as 'Failure Count',\nfail/total as 'Failure Rate', \nuniq_act\nFROM (select \na.cluster, a.db,\nsum(if(a.cpu>a.cpu_l, a.cpu- a.cpu_l,0)) cpu, \nsum(if(a.disk_b>a.disk_b_l, a.disk_b- a.disk_b_l,0)) disk_b, \nsum(if(a.disk_logical_read_b>a.disk_logical_read_b_l, a.disk_logical_read_b- a.disk_logical_read_b_l,0)) disk_logical_read_b, \nsum(if(a.disk_logical_write_b>a.disk_logical_write_b_l, a.disk_logical_write_b- a.disk_logical_write_b_l,0)) disk_logical_write_b, \nsum(if(a.network_b>a.network_b_l, a.network_b- a.network_b_l,0)) network_b, \nsum(if(a.network_logical_recv_b>a.network_logical_recv_b_l, a.network_logical_recv_b- a.network_logical_recv_b_l,0)) network_logical_recv_b, \nsum(if(a.network_logical_send_b>a.network_logical_send_b_l, a.network_logical_send_b- a.network_logical_send_b_l,0)) network_logical_send_b,\nsum(if(a.memory_bs>a.memory_bs_l, a.memory_bs- a.memory_bs_l,0)) memory_bs,\nsum(if(a.elp>a.elp_l, a.elp- a.elp_l,0)) elp, \nsum(if(a.fail>a.fail_l, a.fail- a.fail_l,0)) fail, \nsum(if(a.total>a.total_l, a.total- a.total_l,0)) total,\na.uniq_act\nfrom t a\nwhere total > 0 and elp > 0\ngroup by uniq_act) subq\nWHERE (subq.total > 0)\n) res, `mv_queries` q\nwhere res.uniq_act = q.activity_name\norder by `$sortby` desc\nlimit $topn", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Metrics by Query Plan", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Avg. CPU Time": 7, + "Avg. Disk Bytes": 9, + "Avg. Disk Read Bytes (logical)": 10, + "Avg. Disk Write Bytes (logical)": 11, + "Avg. Elapsed Time": 5, + "Avg. Memory Bytes": 8, + "Avg. Network Bytes": 12, + "Avg. Network Received Bytes (logical)": 13, + "Avg. Network Send Bytes (logical)": 14, + "Execution Count": 3, + "Failure Count": 15, + "Failure Rate": 16, + "Total CPU Time": 6, + "Total Elapsed Time": 4, + "db": 0, + "query_plan": 2, + "uniq_act": 1 + }, + "renameByName": { + "uniq_act": "Query_plan_id" + } + } + } + ], + "type": "table" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 7, + "options": { + "code": { + "language": "sql", + "showLineNumbers": true, + "showMiniMap": true + }, + "content": "${activity_name}", + "mode": "code" + }, + "pluginVersion": "12.1.0", + "title": "select a query in the table above to view its text", + "type": "text" + }, + { + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 25 + }, + "id": 9, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "**Elapsed Time** - Wall clock milliseconds elapsed during execution \n\n**CPU Time** - The units of CPU Time are 'core ms' because it's the time spent running on each CPU core across the workspace. This is likely to exceed the observed elapsed time because the tasks are likely to have executed concurrently\n\n**query_plan** - Query plans are compiled to machine code from the query by parameterizing the values and cached to expedite subsequent executions.
\n      For Instance: Let's say you execute the below 2 queries,
\n        Select * from table_a where colum_a = \"Value_A\"
\n        Select * from table_a where column_a = \"Value_B\"
\n      Query Plan for the above two queries would look something like the below,
\n        Select * from table_a where column_a = ^
", + "mode": "markdown" + }, + "pluginVersion": "12.1.0", + "title": "Notes", + "type": "text" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "0cda4387b1a7", + "value": "0cda4387b1a7" + }, + "hide": 2, + "name": "viewName", + "options": [ + { + "selected": true, + "text": "0cda4387b1a7", + "value": "0cda4387b1a7" + } + ], + "query": "0cda4387b1a7", + "type": "textbox" + }, + { + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(cluster) from `act_samples` where $__timeFilter(ts)", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from `act_samples` where $__timeFilter(ts)", + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "uid": "monitoring" + }, + "definition": "select distinct(ifnull(database_name,'-')) from `act_samples` where (cluster = '$cluster') and $__timeFilter(ts)", + "includeAll": true, + "multi": true, + "name": "database_name", + "options": [], + "query": "select distinct(ifnull(database_name,'-')) from `act_samples` where (cluster = '$cluster') and $__timeFilter(ts)", + "refresh": 2, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "auto": true, + "auto_count": 100, + "auto_min": "30s", + "current": { + "text": "1m", + "value": "1m" + }, + "name": "interval", + "options": [ + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "1m,5m,10m,30m,1h,3h,6h,12h,1d", + "refresh": 2, + "type": "interval" + }, + { + "current": { + "text": "All", + "value": "All" + }, + "description": "Hidden activity name to get query", + "includeAll": false, + "label": "Query Plan ID", + "name": "hidden_activity_name", + "options": [ + { + "selected": true, + "text": "All", + "value": "All" + }, + { + "selected": false, + "text": "Select a query in the table below", + "value": "Select a query in the table below" + } + ], + "query": "All, Select a query in the table below", + "type": "custom" + }, + { + "current": { + "text": "All", + "value": "All" + }, + "hide": 2, + "includeAll": false, + "label": "Query Plan", + "name": "query_plan_hidden", + "options": [ + { + "selected": true, + "text": "All", + "value": "All" + }, + { + "selected": false, + "text": "Select a query in the table below", + "value": "Select a query in the table below" + } + ], + "query": "All, Select a query in the table below", + "type": "custom" + }, + { + "current": { + "text": "None", + "value": "" + }, + "datasource": { + "uid": "monitoring" + }, + "definition": "select case when '$hidden_activity_name' = 'All' then 'All' else query_text end \nfrom `mv_queries` \nwhere (cluster = '$cluster') and \nactivity_name in ('$hidden_activity_name')", + "hide": 2, + "includeAll": false, + "name": "activity_name", + "options": [], + "query": "select case when '$hidden_activity_name' = 'All' then 'All' else query_text end \nfrom `mv_queries` \nwhere (cluster = '$cluster') and \nactivity_name in ('$hidden_activity_name')", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "100", + "value": "100" + }, + "includeAll": false, + "label": "Top N (Query Plan)", + "name": "topn", + "options": [ + { + "selected": true, + "text": "100", + "value": "100" + }, + { + "selected": false, + "text": "250", + "value": "250" + }, + { + "selected": false, + "text": "500", + "value": "500" + }, + { + "selected": false, + "text": "1000", + "value": "1000" + } + ], + "query": "100,250,500,1000", + "type": "custom" + }, + { + "current": { + "text": "Execution Count", + "value": "Execution Count" + }, + "includeAll": false, + "label": "Sort By", + "name": "sortby", + "options": [ + { + "selected": false, + "text": "Avg. Elapsed Time", + "value": "Avg. Elapsed Time" + }, + { + "selected": false, + "text": "Total Elapsed Time", + "value": "Total Elapsed Time" + }, + { + "selected": false, + "text": "Avg. CPU Time", + "value": "Avg. CPU Time" + }, + { + "selected": false, + "text": "Total CPU Time", + "value": "Total CPU Time" + }, + { + "selected": false, + "text": "Avg. Memory Bytes", + "value": "Avg. Memory Bytes" + }, + { + "selected": false, + "text": "Avg. Disk Bytes", + "value": "Avg. Disk Bytes" + }, + { + "selected": false, + "text": "Avg. Disk Read Bytes (logical)", + "value": "Avg. Disk Read Bytes (logical)" + }, + { + "selected": false, + "text": "Avg. Disk Write Bytes (logical)", + "value": "Avg. Disk Write Bytes (logical)" + }, + { + "selected": false, + "text": "Avg. Network Bytes", + "value": "Avg. Network Bytes" + }, + { + "selected": false, + "text": "Avg. Network Received Bytes (logical)", + "value": "Avg. Network Received Bytes (logical)" + }, + { + "selected": false, + "text": "Avg. Network Send Bytes (logical)", + "value": "Avg. Network Send Bytes (logical)" + }, + { + "selected": true, + "text": "Execution Count", + "value": "Execution Count" + }, + { + "selected": false, + "text": "Failure Count", + "value": "Failure Count" + }, + { + "selected": false, + "text": "Failure Rate", + "value": "Failure Rate" + } + ], + "query": "Avg. Elapsed Time,Total Elapsed Time,Avg. CPU Time,Total CPU Time,Avg. Memory Bytes, Avg. Disk Bytes, Avg. Disk Read Bytes (logical), Avg. Disk Write Bytes (logical), Avg. Network Bytes,Avg. Network Received Bytes (logical), Avg. Network Send Bytes (logical), Execution Count,Failure Count,Failure Rate", + "type": "custom" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Historical Workload Monitoring", + "uid": "1xNFf_iSk", + "version": 1 +} diff --git a/samples/speedystore/dashboards/memoryusage.json b/samples/speedystore/dashboards/memoryusage.json new file mode 100644 index 00000000..d8baff25 --- /dev/null +++ b/samples/speedystore/dashboards/memoryusage.json @@ -0,0 +1,812 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 265, + "links": [], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Total_Server_Memory used, out of Maximum_Memory limit.\nUsed memory is broken into data, queries, or internal.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/MAXIMUM_MEMORY/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(202, 199, 199)", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 5 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/Total Memory Used/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\n time_sec,\n concat(\n case when name = 'memsql_variables_maximum_memory' then 'MAXIMUM_MEMORY'\n when name = 'memsql_status_total_server_memory' then 'Total Memory Used'\n when name = 'memsql_status_buffer_manager_cached_memory' then 'Cached Memory'\n when name = 'memsql_status_alloc_table_memory' then 'Data'\n when name in ('memsql_status_alloc_query_execution',\n 'memsql_status_alloc_aggregator_query_execution',\n 'memsql_status_alloc_columnar_query_execution',\n 'memsql_status_alloc_query_background_tasks',\n 'memsql_status_alloc_query_execution_temp_table',\n 'memsql_status_alloc_query_ingest',\n 'memsql_status_alloc_plan_cache',\n 'memsql_status_alloc_unit_images',\n 'memsql_status_alloc_object_code_images',\n 'memsql_status_alloc_compiled_unit_sections',\n 'memsql_status_alloc_analyze',\n 'memsql_status_alloc_arena',\n 'memsql_status_alloc_autostats',\n 'memsql_status_alloc_backup_restore',\n 'memsql_status_alloc_column_store',\n 'memsql_status_alloc_columnstore_blob_cache',\n 'memsql_status_alloc_distributed_transaction',\n 'memsql_status_alloc_dqo_cache',\n 'memsql_status_alloc_external_formatter',\n 'memsql_status_alloc_external_functions',\n 'memsql_status_alloc_fulltext_search',\n 'memsql_status_alloc_json',\n 'memsql_status_alloc_mmap_memory',\n 'memsql_status_alloc_mmap_wasm',\n 'memsql_status_alloc_parametrizer',\n 'memsql_status_alloc_pipelines',\n 'memsql_status_alloc_profile_stats',\n 'memsql_status_alloc_shared_memory',\n 'memsql_status_alloc_spatial',\n 'memsql_status_alloc_spill',\n 'memsql_status_alloc_stack_first_segmented_array',\n 'memsql_status_alloc_warnings') then 'Query' else 'Other' end\n , ' ', trim_host(host), ':', port, ' (', role, ')') as metric,\n sum(intval) as value\nFROM metrics\nWHERE cluster = '$cluster'\nand extractor = 'memsql'\nand host = '$host'\nand port = '$port'\nand name in ('memsql_variables_maximum_memory',\n 'memsql_status_total_server_memory',\n 'memsql_status_buffer_manager_cached_memory',\n 'memsql_status_alloc_aggregator_query_execution',\n 'memsql_status_alloc_columnar_query_execution',\n 'memsql_status_alloc_query_background_tasks',\n 'memsql_status_alloc_query_execution_temp_table',\n 'memsql_status_alloc_query_ingest',\n 'memsql_status_alloc_column_store',\n 'memsql_status_alloc_analyze',\n 'memsql_status_alloc_arena',\n 'memsql_status_alloc_autostats',\n 'memsql_status_alloc_background_tasks',\n 'memsql_status_alloc_backup_restore',\n 'memsql_status_alloc_client_connection',\n 'memsql_status_alloc_code_generator',\n 'memsql_status_alloc_columnstore_blob_cache',\n 'memsql_status_alloc_databases_list_entry',\n 'memsql_status_alloc_db_tasks',\n 'memsql_status_alloc_distributed_transaction',\n 'memsql_status_alloc_dqo_cache',\n 'memsql_status_alloc_external_formatter',\n 'memsql_status_alloc_fulltext_search',\n 'memsql_status_alloc_global_func',\n 'memsql_status_alloc_json',\n 'memsql_status_alloc_none',\n 'memsql_status_alloc_parametrizer',\n 'memsql_status_alloc_pipelines',\n 'memsql_status_alloc_profile_stats',\n 'memsql_status_alloc_protocol_packet',\n 'memsql_status_alloc_replication',\n 'memsql_status_alloc_security',\n 'memsql_status_alloc_segmented_list',\n 'memsql_status_alloc_sharding_partitions',\n 'memsql_status_alloc_sharding_tables',\n 'memsql_status_alloc_show_statement',\n 'memsql_status_alloc_skynet_consensus',\n 'memsql_status_alloc_snapshot',\n 'memsql_status_alloc_spatial',\n 'memsql_status_alloc_stack_first_segmented_array',\n 'memsql_status_alloc_system_tasks',\n 'memsql_status_alloc_table_metadata_cache',\n 'memsql_status_alloc_transaction',\n 'memsql_status_alloc_warnings',\n 'memsql_status_buffer_manager_unrecycled_memory',\n 'memsql_status_alloc_table_memory',\n 'memsql_status_malloc_active_memory',\n 'memsql_status_alloc_replication_large',\n 'memsql_status_alloc_thread_stacks',\n 'memsql_status_alloc_durability_large',\n 'memsql_status_alloc_external_functions',\n 'memsql_status_alloc_mmap_memory',\n 'memsql_status_alloc_mmap_wasm',\n 'memsql_status_alloc_shared_memory',\n 'memsql_status_alloc_spill',\n 'memsql_status_alloc_thread_signal_handler_altstack',\n 'memsql_status_alloc_unit_ifn_thunks',\n 'memsql_status_total_io_pool_memory',\n 'memsql_status_alloc_compiled_unit_sections',\n 'memsql_status_alloc_object_code_images',\n 'memsql_status_alloc_plan_cache',\n 'memsql_status_alloc_query_execution',\n 'memsql_status_alloc_unit_images')\nand $__unixEpochFilter(time_sec)\ngroup by 1,2\nORDER BY 1,2\n", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Total Memory Used vs Total Limit", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Memory used for query execution, code gen, and plancaching, out of Maximum_Memory limit. Query execution can consume the cache, as well as any available memory less than the total limit.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/MAXIMUM_MEMORY/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(202, 199, 199)", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 5 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\n time_sec,\n concat(\n case \n when name like 'memsql_status_alloc%' then trim_metric(name, 'memsql_status_alloc_')\n when name like 'memsql_variables_%' then 'MAXIMUM_MEMORY'\n end\n , ' ', trim_host(host), ':', port, ' (', role, ')') as metric,\n sum(intval) as value\nFROM metrics\nWHERE cluster = '$cluster'\nand extractor = 'memsql'\nand host = '$host'\nand port = '$port'\nand name in ('memsql_variables_maximum_memory',\n 'memsql_status_alloc_query_execution',\n 'memsql_status_alloc_aggregator_query_execution',\n 'memsql_status_alloc_columnar_query_execution',\n 'memsql_status_alloc_query_background_tasks',\n 'memsql_status_alloc_query_execution_temp_table',\n 'memsql_status_alloc_query_ingest',\n 'memsql_status_alloc_plan_cache',\n 'memsql_status_alloc_unit_images',\n 'memsql_status_alloc_object_code_images',\n 'memsql_status_alloc_compiled_unit_sections',\n 'memsql_status_alloc_analyze',\n 'memsql_status_alloc_arena',\n 'memsql_status_alloc_autostats',\n 'memsql_status_alloc_backup_restore',\n 'memsql_status_alloc_column_store',\n 'memsql_status_alloc_columnstore_blob_cache',\n 'memsql_status_alloc_distributed_transaction',\n 'memsql_status_alloc_dqo_cache',\n 'memsql_status_alloc_external_formatter',\n 'memsql_status_alloc_external_functions',\n 'memsql_status_alloc_fulltext_search',\n 'memsql_status_alloc_json',\n 'memsql_status_alloc_mmap_memory',\n 'memsql_status_alloc_mmap_wasm',\n 'memsql_status_alloc_parametrizer',\n 'memsql_status_alloc_pipelines',\n 'memsql_status_alloc_profile_stats',\n 'memsql_status_alloc_shared_memory',\n 'memsql_status_alloc_spatial',\n 'memsql_status_alloc_spill',\n 'memsql_status_alloc_stack_first_segmented_array',\n 'memsql_status_alloc_warnings')\nand $__unixEpochFilter(time_sec)\ngroup by 1,2\nORDER BY 1,2\n", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Query Memory Used vs Total Limit", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Table_Memory used, out of Maximum_Table_Memory limit.\nTable_primary and Variable should be the greatest allocators. The others should be small.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/TABLE_MEMORY/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 5 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/MAXIMUM_TABLE_MEMORY/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(202, 199, 199)", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 5 + }, + { + "id": "custom.stacking", + "value": { + "group": "B", + "mode": "normal" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 8, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\n time_sec,\n intval as value,\n concat(\n case \n when name like 'memsql_status_alloc_%' then trim_metric(name, 'memsql_status_alloc_')\n when name like 'memsql_variables_%' then trim_metric(name, 'memsql_variables_')\n end\n , ' ', trim_host(host), ':', port, ' (', role, ')') as metric\nFROM metrics\nWHERE cluster = '$cluster'\nand extractor = 'memsql'\nand host = '$host'\nand port = '$port'\nand name in ( 'memsql_variables_maximum_table_memory',\n 'memsql_status_alloc_variable',\n 'memsql_status_alloc_table_primary',\n 'memsql_status_alloc_deleted_version',\n 'memsql_status_alloc_skiplist_tower',\n 'memsql_status_alloc_large_variable',\n 'memsql_status_alloc_hash_buckets',\n 'memsql_status_alloc_internal_key_node',\n 'memsql_status_alloc_table_autostats',\n 'memsql_status_alloc_varbuffer_cache')\nand $__unixEpochFilter(time_sec)\nORDER BY time_sec ASC, value ASC\n", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Data Memory Used vs Data Limit", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "Memory used for internal MemSQL allocations, out of Maximum_Memory limit.\nThe cache holds memory in MemSQL for faster internal allocation (eg for executing queries quickly).", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/MAXIMUM_MEMORY/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(202, 199, 199)", + "mode": "fixed" + } + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineWidth", + "value": 5 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "none" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 12, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last *", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "alias": "", + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\n time_sec,\n intval as value,\n concat(\n case \n when name like 'memsql_status_alloc%' then trim_metric(name, 'memsql_status_alloc_')\n when name like 'memsql_status_buffer_manager_%' then trim_metric(name, 'memsql_status_buffer_manager_')\n when name like 'memsql_status_%' then trim_metric(name, 'memsql_status_')\n when name like 'memsql_variables_%' then trim_metric(name, 'memsql_variables_')\n end\n , ' ', trim_host(host), ':', port, ' (', role, ')') as metric\nFROM metrics\nWHERE cluster = '$cluster'\nand extractor = 'memsql'\nand host = '$host'\nand port = '$port'\nand name in ('memsql_variables_maximum_memory',\n 'memsql_status_alloc_background_tasks',\n 'memsql_status_alloc_client_connection',\n 'memsql_status_alloc_code_generator',\n 'memsql_status_alloc_databases_list_entry',\n 'memsql_status_alloc_db_tasks',\n 'memsql_status_alloc_global_func',\n 'memsql_status_alloc_none',\n 'memsql_status_alloc_protocol_packet',\n 'memsql_status_alloc_replication',\n 'memsql_status_alloc_security',\n 'memsql_status_alloc_segmented_list',\n 'memsql_status_alloc_sharding_partitions',\n 'memsql_status_alloc_sharding_tables',\n 'memsql_status_alloc_show_statement',\n 'memsql_status_alloc_skynet_consensus',\n 'memsql_status_alloc_snapshot',\n 'memsql_status_alloc_system_tasks',\n 'memsql_status_alloc_table_metadata_cache',\n 'memsql_status_alloc_transaction',\n 'memsql_status_buffer_manager_unrecycled_memory',\n 'memsql_status_malloc_active_memory',\n 'memsql_status_alloc_replication_large',\n 'memsql_status_alloc_thread_stacks',\n 'memsql_status_alloc_durability_large',\n 'memsql_status_alloc_thread_signal_handler_altstack',\n 'memsql_status_alloc_unit_ifn_thunks',\n 'memsql_status_total_io_pool_memory')\nand $__unixEpochFilter(time_sec)\nORDER BY time_sec ASC, value ASC\n", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Internal Memory Allocators vs Total Limit", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "support" + ], + "templating": { + "list": [ + { + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from metrics where $__unixEpochFilter(time_sec)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "127.0.0.1", + "value": "127.0.0.1" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(host) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and host is not NULL and host != \"\"", + "includeAll": false, + "name": "host", + "options": [], + "query": "select distinct(host) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and host is not NULL and host != \"\"", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "3307", + "value": "3307" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": false, + "name": "port", + "options": [], + "query": "select distinct(port) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and port is not NULL", + "refresh": 2, + "regex": "", + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [] + }, + "timezone": "", + "title": "Memory Usage", + "uid": "memory-usage", + "version": 1 +} diff --git a/samples/speedystore/dashboards/pipelineperformance.json b/samples/speedystore/dashboards/pipelineperformance.json new file mode 100644 index 00000000..5d0b2fc1 --- /dev/null +++ b/samples/speedystore/dashboards/pipelineperformance.json @@ -0,0 +1,1508 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 266, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "", + "type": "link", + "url": "https://docs.singlestore.com/managed-service/en/reference/troubleshooting-reference/pipeline-errors/detect-and-address-slow-performance-and-high-memory-usage-of-pipelines.html" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(IFNULL(run_count,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and activity_name like '%RunPipeline%' \n and (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name))\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(exec_cnt) execution_count\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.total>a.total_l, a.total- a.total_l, 0)) exec_cnt\n from t a\n group by 1, 2, 3, 4) subq\nwhere exec_cnt > 0\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "avg_cpu_time_ms", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "avg_memory_mb", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "ts", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_perfmetrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts)\n and (cluster = '$cluster')\n and activity_name like '%RunPipeline%' \n and (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name))\n and (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))\n and (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(exec_cnt) as failure_count\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.total>a.total_l, a.total- a.total_l, 0)) exec_cnt\n from t a\n group by 1, 2, 3, 4) subq\ngroup by 1\norder by 1", + "refId": "B", + "select": [ + [ + { + "params": [ + "cpu_time_ms" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "08c783c1c927b993824179b6d7a31908_act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Execution Count", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "time_sec" + } + ], + "fields": {} + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(cpu) OVER w cpu_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(cpu_time_ms) cpu,\n max(IFNULL(run_count,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts) and \n (cluster = '$cluster') and \n activity_name like '%RunPipeline%' and \n (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name)) and\n (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null)) and\n (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(cpu)/sum(total) as 'Avg CPU Time per Execution'\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.cpu>a.cpu_l, a.cpu- a.cpu_l, 0)) cpu,\n sum(if(a.total>a.total_l, a.total- a.total_l, 0)) total\n from t a\n group by 1, 2, 3, 4) subq\nwhere cpu > 0\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "avg_cpu_time_ms", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "avg_memory_mb", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "ts", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_perfmetrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg CPU Time per Execution", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "time_sec" + } + ], + "fields": {} + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(elp) OVER w elp_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(elapsed_time_ms) elp,\n max(IFNULL(run_count,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts) and \n (cluster = '$cluster') and \n activity_name like '%RunPipeline%' and \n (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name)) and\n (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null)) and\n (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(elp)/sum(total) as 'Avg Elapsed Time per Execution'\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.elp>a.elp_l, a.elp- a.elp_l, 0)) elp,\n sum(if(a.total>a.total_l, a.total- a.total_l, 0)) total\n from t a\n group by 1, 2, 3, 4) subq\nwhere elp > 0\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "avg_cpu_time_ms", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "avg_memory_mb", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "ts", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_perfmetrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg Elapsed Time per Execution", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "time_sec" + } + ], + "fields": {} + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 8 + }, + "id": 13, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(disk_b) OVER w disk_b_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(disk_b) disk_b,\n max(IFNULL(run_count,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts) and \n (cluster = '$cluster') and \n activity_name like '%RunPipeline%' and \n (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name)) and\n (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null)) and\n (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(disk_b)/sum(total) as 'Avg IO per Execution'\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.disk_b>a.disk_b_l, a.disk_b- a.disk_b_l, 0)) disk_b,\n sum(if(a.total>a.total_l, a.total- a.total_l, 0)) total\n from t a\n group by 1, 2, 3, 4) subq\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "avg_cpu_time_ms", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "avg_memory_mb", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "ts", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_perfmetrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg IO per Execution", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "time_sec" + } + ], + "fields": {} + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 8 + }, + "id": 11, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(elp) OVER w elp_l,\n lag(memory_b) OVER w memory_b_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(elapsed_time_ms) elp,\n max(1000*memory_bs) memory_b\n from `act_samples` act\n where $__timeFilter(ts) and \n (cluster = '$cluster') and \n activity_name like '%RunPipeline%' and \n (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name)) and\n (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null)) and\n (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(memory_b)/sum(elp) as 'Avg Memory Used per Execution'\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.elp>a.elp_l, a.elp- a.elp_l, 0)) elp,\n sum(if(a.memory_b>a.memory_b_l, a.memory_b- a.memory_b_l, 0)) memory_b\n from t a\n group by 1, 2, 3, 4) subq\nwhere elp > 0\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "avg_cpu_time_ms", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "avg_memory_mb", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "ts", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_perfmetrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg Memory Used per Execution", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "time_sec" + } + ], + "fields": {} + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 8 + }, + "id": 12, + "options": { + "legend": { + "calcs": [ + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\nSELECT *,\n lag(ts) OVER w ts_l,\n lag(network_b) OVER w network_b_l,\n lag(total) OVER w total_l\nFROM (\n select ts,\n cluster,\n activity_name name,\n database_name db,\n max(network_b) network_b,\n max(IFNULL(run_count,0)+IFNULL(success_count,0)+IFNULL(failure_count,0)) total\n from `act_samples` act\n where $__timeFilter(ts) and \n (cluster = '$cluster') and \n activity_name like '%RunPipeline%' and \n (activity_name like '%${pipeline_name:raw}%' or '%' in ($pipeline_name)) and\n (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null)) and\n (activity_name = aggregator_activity_name or aggregator_activity_name is NULL)\n group by cluster, database_name, activity_type, activity_name, ts) q\nWINDOW w AS(partition by cluster, db, name order by ts) )\nselect $__timeGroup(time_sec,$interval) time_sec,\n sum(network_b)/sum(total) as 'Avg Network Bytes per Execution'\nFROM (select a.cluster,\n a.db,\n a.name,\n a.ts time_sec,\n sum(if(a.network_b>a.network_b_l, a.network_b- a.network_b_l, 0)) network_b,\n sum(if(a.total>a.total_l, a.total- a.total_l, 0)) total\n from t a\n group by 1, 2, 3, 4) subq\nwhere network_b > 0\ngroup by 1\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "avg_cpu_time_ms", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "avg_memory_mb", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "ts", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_perfmetrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg Network Bytes per Execution", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "time", + "targetField": "time_sec" + } + ], + "fields": {} + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "error_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 113 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "error_code" + }, + "properties": [ + { + "id": "custom.width", + "value": 102 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "error_message" + }, + "properties": [ + { + "id": "custom.width", + "value": 496 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "database_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 194 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 6, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "PipelineName" + } + ] + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT pipeline_name as PipelineName, \n database_name, \n error_id, \n error_code,\n error_message,\n from_unixtime(error_unix_time) as error_time\nFROM `pipeline_errors`\nwhere (pipeline_name in ($pipeline_name) or '%' in ($pipeline_name) or ('-' in ($pipeline_name) and pipeline_name is null)) and\n cluster = '$cluster' and\n $__unixEpochFilter(error_unix_time) and\n (database_name in ($database_name) or '%' in ($database_name) or ('-' in ($database_name) and database_name is null))", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "pipeline_name", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "database_name", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "error_id", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "error_unix_time", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_errors", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Pipeline Errors", + "type": "table" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(cluster) from pipeline_metrics where $__timeFilter(ts)", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from pipeline_metrics where $__timeFilter(ts)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "uid": "monitoring" + }, + "definition": "SELECT distinct pipeline_name FROM `pipeline_metrics` where $__timeFilter(ts) and cluster = '$cluster'", + "includeAll": true, + "label": "Pipeline", + "multi": true, + "name": "pipeline_name", + "options": [], + "query": "SELECT distinct pipeline_name FROM `pipeline_metrics` where $__timeFilter(ts) and cluster = '$cluster'", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "monitoring" + }, + "definition": "SELECT distinct database_name FROM `pipeline_metrics` where $__timeFilter(ts) and cluster = '$cluster'", + "includeAll": true, + "label": "Database", + "multi": true, + "name": "database_name", + "options": [], + "query": "SELECT distinct database_name FROM `pipeline_metrics` where $__timeFilter(ts) and cluster = '$cluster'", + "refresh": 2, + "regex": "", + "sort": 1, + "type": "query" + }, + { + "auto": true, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "1m", + "value": "1m" + }, + "hide": 2, + "name": "interval", + "options": [ + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + } + ], + "query": "1m,5m,10m,15m,30m,1h,6h,12h,1d,7d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Pipeline Performance", + "uid": "pipeline-performance", + "version": 1 +} diff --git a/samples/speedystore/dashboards/pipelinesummary.json b/samples/speedystore/dashboards/pipelinesummary.json new file mode 100644 index 00000000..dddc686f --- /dev/null +++ b/samples/speedystore/dashboards/pipelinesummary.json @@ -0,0 +1,619 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 267, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": [ + "value" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT state,\n COUNT(distinct pipeline_name) as '' \nFROM pipeline_metrics\nwhere UNIX_TIMESTAMP(ts) = $max_ts and\n cluster = '$cluster'\ngroup by state", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "name": "COUNT", + "parameters": [ + { + "name": "state", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_metrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Pipeline State Distribution", + "type": "piechart" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "# of Pipelines", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Stopped" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Running Fo" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true, + "sortBy": "Last", + "sortDesc": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__timeGroup(ts, $interval) as time,\n state,\n count(distinct pipeline_name) as ''\nfrom pipeline_metrics\nwhere cluster = '$cluster' and \n $__timeFilter(ts)\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "cpu_time_ms" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "08c783c1c927b993824179b6d7a31908_act_samples", + "timeColumn": "ts", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Historical Pipeline State", + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PipelineName" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "d/pipeline-performance/pipeline-performance?var-cluster=[[cluster]]&var-pipeline_name=${__data.fields.PipelineName}&var-database_name=${__data.fields.DatabaseName}&${__url_time_range}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "PipelineName" + } + ] + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "dataset": "metrics", + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT pipeline_name as PipelineName, \n database_name as DatabaseName, \n state as State, \n create_time as 'Created on', \n ts as 'Last State Check'\nFROM pipeline_metrics\nwhere UNIX_TIMESTAMP(ts) = '$max_ts' and\n cluster = '$cluster'\ngroup by pipeline_name, database_name ", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [ + { + "name": "pipeline_name", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "database_name", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "state", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "create_time", + "type": "functionParameter" + } + ], + "type": "function" + }, + { + "parameters": [ + { + "name": "alter_time", + "type": "functionParameter" + } + ], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "pipeline_metrics", + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Summary", + "type": "table" + } + ], + "preload": false, + "refresh": "15m", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(cluster) from pipeline_metrics where $__timeFilter(ts)", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from pipeline_metrics where $__timeFilter(ts)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "1693284241", + "value": "1693284241" + }, + "datasource": { + "uid": "monitoring" + }, + "definition": "select UNIX_TIMESTAMP(max(ts)) from pipeline_metrics where $__timeFilter(ts)", + "hide": 2, + "includeAll": false, + "name": "max_ts", + "options": [], + "query": "select UNIX_TIMESTAMP(max(ts)) from pipeline_metrics where $__timeFilter(ts)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "auto": true, + "auto_count": 100, + "auto_min": "10s", + "current": { + "text": "1m", + "value": "1m" + }, + "hide": 2, + "name": "interval", + "options": [ + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "1m,5m,10m,30m,1h,3h,6h,12h,1d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Pipeline Summary", + "uid": "pipeline-summary", + "version": 1 +} diff --git a/samples/speedystore/dashboards/queryhistory.json b/samples/speedystore/dashboards/queryhistory.json new file mode 100644 index 00000000..0420b23e --- /dev/null +++ b/samples/speedystore/dashboards/queryhistory.json @@ -0,0 +1,394 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 268, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [ + { + "options": { + "total_time": { + "index": 0, + "text": "Total Elapsed Time" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 50 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "activity_name" + }, + "properties": [ + { + "id": "custom.inspect", + "value": true + }, + { + "id": "custom.filterable", + "value": true + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/duration/" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "gauge" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "query_text" + }, + "properties": [ + { + "id": "custom.width", + "value": 538 + }, + { + "id": "custom.inspect", + "value": true + }, + { + "id": "custom.filterable", + "value": true + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Query_plan_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 158 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/error/" + }, + "properties": [ + { + "id": "custom.filterable", + "value": true + }, + { + "id": "custom.inspect", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_ms" + }, + "properties": [ + { + "id": "custom.width", + "value": 172 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/name/" + }, + "properties": [ + { + "id": "custom.inspect", + "value": true + }, + { + "id": "custom.filterable", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "resource_pool_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 176 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "custom.width", + "value": 78 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_time" + }, + "properties": [ + { + "id": "custom.width", + "value": 158 + } + ] + } + ] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "start_time" + } + ] + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select start_time,\n activity_name, \n query_text,\n duration_ms,\n database_name,\n user_name,\n resource_pool_name,\n success,\n error_code,\n error_message\nfrom query_event_history\nwhere $__timeFilter(start_time) AND \n cluster = '$cluster'", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Query History", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": { + "Avg. CPU Time": 7, + "Avg. Disk Bytes": 9, + "Avg. Disk Read Bytes (logical)": 10, + "Avg. Disk Write Bytes (logical)": 11, + "Avg. Elapsed Time": 5, + "Avg. Memory Bytes": 8, + "Avg. Network Bytes": 12, + "Avg. Network Received Bytes (logical)": 13, + "Avg. Network Send Bytes (logical)": 14, + "Execution Count": 3, + "Failure Count": 15, + "Failure Rate": 16, + "Total CPU Time": 6, + "Total Elapsed Time": 4, + "db": 0, + "query_plan": 2, + "uniq_act": 1 + }, + "renameByName": { + "uniq_act": "Query_plan_id" + } + } + } + ], + "type": "table" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct(cluster) from `query_event_history` where $__timeFilter(ts)", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from `query_event_history` where $__timeFilter(ts)", + "refresh": 2, + "regex": "", + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Query History", + "uid": "efacc80e-2e33-4bfb-99fe-223b45e4197a", + "version": 1 +} diff --git a/samples/speedystore/dashboards/resourcepoolmonitoring.json b/samples/speedystore/dashboards/resourcepoolmonitoring.json new file mode 100644 index 00000000..dafe6869 --- /dev/null +++ b/samples/speedystore/dashboards/resourcepoolmonitoring.json @@ -0,0 +1,717 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 269, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Documentation", + "tooltip": "", + "type": "link", + "url": "https://docs.singlestore.com/db/v8.1/en/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards.html#cluster-view-793226" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [], + "targetBlank": true, + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l\n from (\n select max(tg) as time,\n max(value) as value,\n metric,\n pool_name\n from (\n SELECT time_sec as time,\n $__unixEpochGroup(time_sec, $interval) as tg, \n host as metric,\n labels::$pool_name as pool_name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n name = 'memsql_resource_pool_status_finished_queries' AND\n ('%' in ($pool) or labels::$pool_name in ($pool))\n )\n group by metric, pool_name, tg) X \n WINDOW w AS (partition by metric, pool_name order by time))\nselect time, \n pool_name,\n sum((value - value_l)) as 'Finished Queries:'\nfrom t\nwhere value_l is not null \n and value >= value_l\ngroup by time, pool_name\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Finished Queries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(value) OVER w value_l\n from (\n select max(tg) as time,\n max(value) as value,\n metric,\n pool_name\n from (\n SELECT time_sec as time,\n $__unixEpochGroup(time_sec, $interval) as tg, \n host as metric,\n labels::$pool_name as pool_name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n name = 'memsql_resource_pool_status_killed_queries' AND\n ('%' in ($pool) or labels::$pool_name in ($pool))\n )\n group by metric, pool_name, tg) X \n WINDOW w AS (partition by metric, pool_name order by time))\nselect time, \n pool_name,\n sum((value - value_l)) as 'Killed Queries:'\nfrom t\nwhere value_l is not null \n and value >= value_l\ngroup by time, pool_name\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Killed Queries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "SELECT $__unixEpochGroup(time_sec, $interval) as time, \n labels::$pool_name as pool_name,\n sum(value) as 'Queueing Queries:'\nFROM metrics\nWHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n host not like '%leaf%' and\n NAME in ('memsql_resource_pool_status_queueing_queries') AND\n ('%' in ($pool) or labels::$pool_name in ($pool))\ngroup by 1, 2\norder by 1;", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Queueing Queries", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "WITH t AS (\n SELECT \n *, \n lag(total_queue_time_ms) OVER w total_queue_time_ms_l\n from (\n select max(tg) as time,\n max(case when name = 'memsql_resource_pool_status_total_queue_time_ms' then value end) as total_queue_time_ms,\n max(case when name = 'memsql_resource_pool_status_queueing_queries' then value end) as queueing_queries,\n metric,\n pool_name\n from (\n SELECT time_sec as time,\n $__unixEpochGroup(time_sec, $interval) as tg, \n name,\n host as metric,\n labels::$pool_name as pool_name,\n value\n FROM metrics\n WHERE $__unixEpochFilter(time_sec) AND\n (cluster = '$cluster') AND\n name in ('memsql_resource_pool_status_total_queue_time_ms','memsql_resource_pool_status_queueing_queries') AND\n ('%' in ($pool) or labels::$pool_name in ($pool))\n )\n group by metric, pool_name, tg) X \n WINDOW w AS (partition by metric, pool_name order by time))\nselect time, \n pool_name,\n sum((total_queue_time_ms - total_queue_time_ms_l))/sum(queueing_queries) as 'Avg. Queue Time:'\nfrom t\nwhere total_queue_time_ms_l is not null \n and total_queue_time_ms >= total_queue_time_ms_l\ngroup by time, pool_name\norder by time", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Queue Time per Queued Query", + "transformations": [ + { + "id": "prepareTimeSeries", + "options": { + "format": "multi" + } + } + ], + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [ + { + "allValue": "'%'", + "current": { + "text": "memsql_cluster", + "value": "memsql_cluster" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "includeAll": false, + "name": "cluster", + "options": [], + "query": "select distinct(cluster) from metrics where $__unixEpochFilter(time_sec)", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "select distinct labels::$pool_name\nfrom metrics\nwhere name = 'memsql_resource_pool_status_finished_queries' and\n $__unixEpochFilter(time_sec) and (cluster='$cluster')", + "includeAll": true, + "label": "Resource Pool", + "multi": true, + "name": "pool", + "options": [], + "query": "select distinct labels::$pool_name\nfrom metrics\nwhere name = 'memsql_resource_pool_status_finished_queries' and\n $__unixEpochFilter(time_sec) and (cluster='$cluster')", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": "'%'", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "mysql", + "uid": "monitoring" + }, + "definition": "", + "hide": 2, + "includeAll": true, + "multi": true, + "name": "host", + "options": [], + "query": "select distinct(host) from metrics where host is not NULL and $__unixEpochFilter(time_sec) and (cluster='$cluster')", + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "auto": true, + "auto_count": 50, + "auto_min": "1m", + "current": { + "text": "$__auto", + "value": "$__auto" + }, + "name": "interval", + "options": [ + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Resource Pool Monitoring", + "uid": "b706aab4-2dc9-41f0-89c1-2418f8da5005", + "version": 1 +} diff --git a/samples/speedystore/images/02_MG_202508_metrics-database.png b/samples/speedystore/images/02_MG_202508_metrics-database.png new file mode 100644 index 0000000000000000000000000000000000000000..06bf140b3d9f8292c6f7911a3928a7592693bc48 GIT binary patch literal 73873 zcmZ^~b980jwlx}6?4)Abs$j=f#kP|QcWm3XZQDu3c2cozTlMlg_n!OC`|kJt*lV@6 zT3d7XImeuR^nn#7FDs4!ivtS+0)ikZA)*KZ0)7Mn0*V0*`Sk>%=8zf$1SZW~SXkcN z$Or_)HS;1(O+IlHC;0c@9G(f}U%{EdnPfk)1ngzw3rc$?Vg<46nTR83YyCqd6d_Q) zY1=x%)Q5*tL5c{1-ucskjkULimzG-PVS1ELl{qvySxV^=J9SrlVuCQaehmdeWtv3VZFfi`?zOjD zR$!m&kD>@epcE&_*>{lQdmEV-WZxME z->J>tO`%30Iz=F;ax3PY_cl0>XDfd2LOmdovEbzLP(UUSG$trZTM)Ht2!7~bnVw)X z2@nEf0fzHHFe-mV0LUMCsHhoupe;`OHlDVBg)Q1;4;7C;OlojSEy$HVwjeT?kmzwJ z8A(hjk!C1ppAa1i)BygCpnn__8LXtpT&%V+rea_s@gE7^xybjxOi>2nr8t9qP?oR> zVjmJh1^AzW*rjyk;ivg@3y@C2A2U&A=;@Ka3SN$N8&QD*a`{=u{tNwnb=d`Fasm{OtxWdzqe9oLtVmJqjN-g zgbeQuUR$`Lb^hSPB8-^s#oR;MS-Zi!>3^nvC-D=AB{M^zgU$}L6{5-Wl@|p_whCYo zOQUU~eG9!60naC84osDpAXP=y3hf#|*@d@DBa>DnPK)D_#8bp53tW&mCElQrNk|?g zF=ng(wi1IUwJBLm))H3}OPH_)4Gm2Nn+od+HvoN(T#61Lx0TUX+y)O4n=M>c5TZ6u z>`L5Aj7Wq^a<R%HmAw(m@ zE|d{iA4C&41-*fhj!6Mi0lNkh0%wC(jlxIE!_Y}3ggJ|OgD#0ojbV<`#=s&)I-_ik z$cjjx0WI@$x6*LUqscAT9hV<_JNw7YMj=C>WHR=hF_VutX4T+1+g5yl&-A246^)E z^+GXAB|+XnVO-Tx#iLSIrA1Lr)kgkziQkgG`G7gzTx&s?1&+Cx<)YcR60GtRw0*k`Ffn>n?IF z@<=*Srcc^JW=I1*8M7kQX%gMk!m@qiKJx_Xhf#xa!~8FwRLhLvw3gKAY9*~flmoBEZ+MTe<|RfoS(l9u3=L`(rpIgY%h_896JtWtiZd{aYP zs;d6@I!1ae7A>Zi>6biD1V{`0e~f+)?>*3*p)I+%`Ikf-c~4X7TIi1I{&wB#>gu%Y z%y~P0+kb_Bp7Y{(Ykuy&Yj~i&@z}4q%sJe`Btl2VnZc_?HzQQX0H74&HnJW6s#Ug? zwsnCfCL=1OHnt1s4+h6A7LF2v6B=eO2TrWJdL=9rKg%3(zyT4rJSpHYF|Zakbng4qGwSSuUjuMU6G~trA5SK1|GoxA(VWx0{!+>wgj$Gk%l$oN||3X~IFk zxqjR0m~>h4iuvF>e9Pmtd{Vx6Q5>P}R47zaR=6)q)$!be`XHq7QD4Drb15BY-M6Lg zX03Cy%K6icW>y#T;8J8w{H>Q}-YZGe*U>oUF z*(OS*_=xKLEqJ?Rz00HxEtbhW|nICwGER1vMlh_no^-TKS! zV%@3X%+#jV+Hr%mdxg`Cb=hwGSamq|M*awxu(shMeRU6CgL{czhtuY`^m+NmgW<_K zx|$H5;Eu3^pMZ#6lR>^dR5ghdY5`_FTeSD)+dd*R3a z_Kz*onBrw6Mjxq{i+RUShts=o?3c7djer#ghiC^ET`O1S50;aIThHDrlHW_+iarl_ zgo{4#3=s6vzYn`~UmBjH_A~Zu5Vjua-Rb$fQm(Dt%C5Wi-_Quv2_g9)y)!kYo<*LO zUo`d{rZHO>W7JSpRiAZzufF}Cmo^Z7%Qxo_Vm`E(are8!HBSMS)G1qsT~$lH*ITAjM%?mh(56R zs~KAeUs?^uRzkx81O##5pC4!vEg~)m2oZ>+h@i4-=6M&CC%Sku@5H6g)|%JW+BP)% z<7&s_FApGph|U^d2R_v}Uxr0jnuWqtS{5uY7MaKo0u?os3IY{7E}<{7UVe)6NHRU` z?!)?F!3;f401W==y2Gqk*vaYPB%9C4X5)0hG8jL8*AN*M2ewIbatPRir;o@4l?pxq zdI;j+%Q>@yCts%0THGFOnHP1@&IR3TKnxuvPt2+qH6x+It2E1^Xa`kP_oan#FtOKLGdOwc>t3Ru(GcV97W*rKsGoH_4Gd^Zxl#-i)tTVYvu7L7TE_Gu<>zb2fs>VW}|3T4Q}7Wvk@9rfMbI?B)u zsZCwDSv8uKm}_uxn*{hQQ7J(RZFA3j`|R@k%Rt-du)Eq?CIgoaf)+*7=C=}rOZJlG zR)qgqM%y<$XtfaHO38-MW%(qg3SS^u^I7sNpFO`pV-C~ny1abIO6mpQg&6`wCl804 z?3i2G+OYKl&axwqIyV*$aQI5cv*zwj*NZXCfjZcj5&yw6I53z90BG$Ff*>U$6T$LA zf<;7KG~;Hs4p`d;xfx$Inh?tJVS0uN;QTL>de`HbX{LT*$TPDJn&oS>F_Lo=R$v^o zS2`$NT{(rY*|?ENrB#6FE3hU_w2?^-Sy=`q|0xteLL+!6?mV?xhdhOw4?tu=6`Rq9=vBsdjXW4Dpp(+oMOZp#-F%A(ijCyg3aZ` z+G}nT3n!`tl14q|SGrToMP&&-QG`bQ=1m``)*@ayU_NZX&(v3n#o7(4Rb>+`Sse|R z490)q)yYf%fki?R7Ze07w=B<{T@#`8P-NV|D_@~H;S$fi3|%;3s1#{svL@SMH%Y&WyAwH2$WsYwW#I$tZ| zG#y7-MGdA`S4WAyQcPIYh;3D@+A?bP6S&gd#)5kt3e1&kd&09n|Tor@L~P$4ZTe{>c>qUe&y7WkOlGNp;d2(TYA+ED4Eesi>%`8 zNV0vry|ouj)Cxp~*~W=@QY`r+TrmqXzpxB#B7;Vf4dKFzvJuIKzBw6gSHuvNq5;u; zaqA%`F#K!ESD6X9whq8yOjKHyC)R6oUg+VYr*+ah%D+ z@!s!~*USo7HdornsIRfBfoJsAMrL?TTQM>oEHtS8`&d<+l zoi8*iwOSA>)M|#hz1{{q+{8s2enxrj^nJqv*a`sZfH9&!_+Or%L(S9INM>ws7G;Ct znEu|5GtQPNm54ny!u;uYfqqtkUH_!T zsrHE!XtV?!!$?(dldOQg$KW|uZXPv84eN>&D}YugHo0$M>x<+$Y~(k&Zhp9)H`SzA z8m&J8$T+h%&ZX0&j9JRGHC|O^?gbbxnuS6x)fY7bBLI}LXn#LGK5k~k3Bz=`+lgO# z$M~!NhgJUDm-#*J37DCcBKN>y(Dekupj}ULY(e9)S)dO^;f6394e1|EWy!cVtx07n zp+B!QnBH9Z{KaKpV33fIK)(9iA1!hBdOay=+2*tn%#;H4dc8NV!20_#?XxM7J8m+~ z`=nign=5H2E3{S`L{S9khDL+(=*%4bJ2j%h2sTeM1!@|}XlMD1W=@Aj0RT2bc9P4+ z#yBIn&Be*N^Mz#Kc(y=rx!sA@`Fxp}Pfb-7c1J}?$>_VqeOG(CW+mzJ+FHaNaj*3F zh?xg!pTprquVqbF@WFUW#0OP_i-txTfO0iBIZl$9DkZGeecY5QnWq{3NU212@T}%H zgS)R8?_`%u-XD8@jbyr%MHD=Ie7lo5@>wZiUI_>;$UhncM}lna6!i%E6Cm}%{mnXG z%iwc6N+}^L`$Zr81Mk8U|EUSKyZ3u0?c<&H>x6}b0rKW3i^oPrj%%OnxEMsoAR!>O_5QwMvfFIZMT_IaHTFE5Ev=n*{VoHPfD`b#qfhhP z!9yb81TyHf>yN||_a*S@_kb9HLm`Uf@OfSL!7;9XF=|23P_AH@CAp9;ZOq{z~#`5iGI;X{&GDT@m>6pcj!PUZ|oCwt9ks@{^Id|GodhJUPh&oY#O4!=kBI85X zYu|Q%K~qMSNfvb~Vli&3mxaS*2uw*yX_B_k(i*9JcG05RGEc}NASWj$X%7I<+np~n z(`h!AO4hhr4svcd4tVVTcu33w*a@x2YG`N};=xyuT3SwH|C>VoM{)IZjewqTQe4b4 zVPex4+$`d!5pjMwcf5!J&MuE}WEa$d!kk}|=|Ly+B`&3a6tJwRhmkna=l8p5X4h-| z`?Dn^wHn>;tGQLWZyDhZw}DC%d|`H{QLa~APa@MI{eDmT5vvhag25J)N&8Il`l(qlemt?DU7g-JWm#*3<5k$zX?> zmDbhK_?;&l0?WwbH}t~)cHV%+ZiV&!{$9E3u~e-Ca5#(v$dxa(YLuyels_n$_$&En-e2`MGBW>K5#!MNT#oe`w%zyJgK>b< zX(Cm~YEJcR$5l72s~8fTrmWbOM()-JA=QjSt^C$$=azsg-Au5-g4tOJU9ibOX=jy_tPE@E?p>9ztXAaOtffLzD`zJBb=xCoF z09-CJmye24bWu$vvU#;aTWh*sVbLgM(Yu()#)_7bBqR*>$%@TA!JEL{6sg;NQNd%? z3qrxU)L>O8cjY}$!>Hl2R`2#l6Y_bq{QfZ}Y_A+X$(GksRx9G>=4Sq$ufRk8p5iiJ zT#V3?IUyH8l9c2t6({JQFo^efaw#UCPtUrm0II1X6sq&g)ziHgevGB|B6f4h%y9zY za4XlnC=QXMg}1BUjC}l$%SO9c_qHSjh^XxZ1K`=eqV%AjgZ`~`{v`r>|`}hWJ4X?Yf9W_Zbm>QxB~9+MK$Jc5pOaR zQVRp(klo%cT7u3to$>snaa`7R*GolBejz;mWrKOlGR)hQhyHP2%CHpbHZ>Zc3rEl5 zb>DiQh+TJ;rjS$~GPU4%=!~k39xjW;?OZuRB?p$$cfVAl#|U|iCQ+JTOR~ct+$$NG zuw4{udMh;Vg4()(CN%oZIF&0&&ftTrcBxV$AUqtF_;b{VUQj4Y^U zY_A6N!xvw&)?7d=tf>A^jLLDVu@U(3(ZuKg6a2%=-FBrcaRyjg3!qPd=k6ABgi?? z6Ii4Fp=kdr!m}*_5S6SZ_jBNCYW=!t{|*NOgAy$tj#mt=x>oD#&Pb^vf)f)A>9X+b zQf4ZdnxGV&>3u&X_Zl&jYqQ>3H#twcrL?PEu_UCG=eKnQ)?SG-@gt^hgHkS=PKZOoR{@NjCINyeh;{zck&kRdk`9fSiZ#n!c704?tA8tn_CLb>Uz=6n4aP`LPVW91`p*nQ?_xU&YGP$z!8;K(vFH^q733TYktn{^fMNaq%n5YtlphK zL5f;>VSdgRv?_tjSlSXXv^x%5qnQG7PAZk%ATj*iX8C`U5C72aIyRz+s3;riZ+paB z?(a=MUj|1MXoQzfY8FO-yxtWhillP%L5@l_5Ndg%IV(_=d;k|AfL2s84<&KV!+^}*OHCyZhGEYzwe zjMzZ{B`>P?ES@ch)#%Q07SeXQadzB}`}Q&T>t^f)82e4Tmo|f6u39K7OyeEEHsxaY zc^ewIPHl?G$M=J}t7iFbEecU~7)J|_woE>yXU?c6n{qGp%)1!czpekr1eu@~TyhaK z(T|!*(uMNP@#x9rNb?we+{P(DGrE;fN47WdqRWIkNX>C{2|`6xL#Cvd7!Ehs*}iL_ z;&B!AUzoaGdo@ECNPUI3=DC)!MP1aSvnJd*t(k=D&e^s&l(MM^fBEx;3;LLI@Q<3IB$|BifWp^6c>9#ZRIIY|2L z9#+}DRGU-kHz+7L1z{tXyW87kBX1;V+2-aJK{2u5&{rY`m;H~v{|gjo_uSQ7rN1wT zr8M+nn(o1=YaIo2l$7Fukn@>q`^=^WBfHNfBcQw1Zf=~ncXy)q;{QK@D*pk5pwljy zwxm@e3RG?O=$%YDDR^ zw6Ks@Q1FY7N8LX>3_saWR8m^`kIdb_rQd{~M=*F=TAE=h)1<44ii(L7%O+4}uo&3F z?n*S+b{~)V{d*XM9{QGC&Vj2d;?Z_2#=pYv|9Sr(Z@aC#3*x3KnW|(Dw5L-1Bt<>R zoR;!fdLWOuTf0w2OQSBsM9J#aXTpMq4EVZv|17PpZsx-Fu>jNIk~-^qcp!mFcj{W9 zlcwtk2@zj1Yb>?yD=%*fND-z#r~_N2CRKEFf^KgW6VWmA8XK{alD_x((Mgx{p(1XVwOY#C&BUoDMe9^xMApF~!9|G?slT|@A||*H zb}D9aeq|Vy9xu~IJtJEO^3Ut7hIF0%*Q~x^6p+VS$K}7s7Sz_tM~d4pBDF8LUzEK# za#f|q0~k4=%0^*A!{CJ-1922kEXdYF#bkfsj5%p4UpxvP?!}PqE&UcN3IJy<{8mQr z6e~a(!wIjcJ+@>Zo=%`!=6)_c+y6rpYT6h-6YO^9G9$=;*W&mgJoXCNPPT8|d0p5e zhbl=jR)~w4Ss}6_7k(u_TSX-w5lEl%Skksg{etTU!Jj025J!}9Bs!d=)Ge9EFl_&C zlVHII)8oM2c973Vo_$45NPe>J5?m5%;;Coy>aijF1Az6=XaON@c+@>3J5mbN8;<-q zbRTf$uUigsOr~kJ;Lj3SiI0`(*q6T_KBbYN$eWHA^kzNLwdFX2Qr>_zNV&_hzQ68j zJ3cO|yFNTL*W+19&x5Bt@8<{O$MUVkVO8;i%4>Gk0(#GpUeV7=8&LQ=AKDvNutPBe>N1J>r3vfS8^EHUAnkt~Te ztiuWUZ^x5(s=qyc;D*xe=tuV{mE?Zb7`mTgQuLcX;~Whz#cQ1!xXH7|X(X#Xfrrt? z?AQj4=fW4j_9`5WF;*Od(yA)%;uW$}q9wMXpvGSiru4`Q#m}tZ)|7Nj;^5-Oi^%kDJ)8D~KBIAYtc;G@m-Y>Es(z=_ z%bMm!xrDWr@~AWZD^0qZomY%->zE^oe~tzg{-YpBB$)Pa-j1$Xr*R6`R-68n zACxHgxMAx9BKw~YH4+yKFy{P!Iavt3(39%we!9N#5>1U7Sua?|=_v#(Ie*{%jc0#z zT&&G=o*5C6Wq&=Atj)thhdS*|5LnU;FaD$fLq%2X=l57eA@0Z>=HQkWA0N+Tu|S2# z>%Kr^zcz2wZMP>Toz4pLm2^VO*LVbbd3iCo-5)*vQ-P_iqq9afRfMSu{(=h^l_wtWROo`2mt16Ex0!SwTtov7t%bes#w*2Nrs%)2fv?`T1 zHV2O%{}6;7zYwf#`r-LZo-n}qJQaB!{l&7QoBklKJKmj?j!rss-`5u;&m6k3y2!pP zKtK$?MYJR?A<+><6g45?_A7)&i&pgU@ljxK+b{CA=o*?2MGUB~S0p1}7qC)pMLsOw zK3hJnC7?~A?@d>st#uz{snqO7rv!^8V&lL~@^~aVI@uyUn-y0$IERlKb({`tjIe#w z#BUZy-}}u$wsSKH>18Q`~PxY}cfB ze04@Xazugd?d`>4HAAk}`_0h3_0!c&s?TRUnZD1+nl|5@H_k7*%j?bA@pNI7CR2-a z$^;dFdIUkj^GC~lFsxC;(A3n_)zvlhqOZT7*>nnTU|>MK|M=kXq3dXW<2$|Iyfq>q zMJR16ibH4lynU*>vsG}#wC&(U33(;n!<-0mF!?qzn9AZD{zBI zgCx2e->Rz2-V_8t3<6_PlS|DHeK!<2=rl`df;@|u@42RnGAgWT zio2uF8$6f%^G&n($*k2!=?urVq#9TzW5(%rf5JsG+(aP!&PKGqp!=*hi8gM5FxECl zBdkb-w+{a8iTY>1J8hW9u>GWju_h@%nu>8uSfeR#ldVci@9(g}dPQR`7v!eLGzrB% zy7LQO2#Y}Qvz9-2HZBTX`7hKX+Odiz>X|d)>6LZ`jyfJ15ZeZ(bjKKxNb`aU? zF?Tm6RMC8pF! zI>|A8_Aeq89jZ;qEPK=E!Ebg&(gEGgvki(11-j_beWq*9mdzJ!lz#uPWDE2Qw^&$l z3?3)RJ%l-;{qx0IiyWC*!$x)0LHsAtg)qSFmh7t)D&k=DpiphZLpHsrX*aXE37_$| z;UKKla;;$K`{&1-R?0YV_0abZ2_q$(U7bQ`I5gVMIo~FCo#BZgpi&F`jjdu(uOn%E zr*V^DryQBg#Ds{S6J=0Rvb4Oat0>TxKC43-#JghkPwu>dnJ?^gYu3OPPxRgu0jO*5 z9klK(XDH^|^x^yN$;hsctu30Q|ep2WF zE!0!dEP;pwRCfRF@ezYpiQD=7tN2pVS|(9T$m3cYms-<7T?qKI9okQlDXq8~7#Q+g zIPU+3A+9Z}0^v1hCk`Npws;(}I9Vi*lazPsFnl5};)v$@Hg&Zc9fG-5 zsH98YI-$8a7>0|a51^~^%p7)JTHs!^CHa~#WiO8gj>e$*=^U>`!?s25E=a#wFDTf! zUaE2FPbSM|t&exqn!ia(mFNeU@`o9}R*Vm9R^i%__oHr_rWMy8w{x6#$@b6jDz{`v zQd7}; znqL(7>_s`5uUdhEg+&#-8t)J<(C;8w5etVYgY!YKbg)Z zWa;(rM=c+|uTrC7romKhB8OkEl5|64*jna=MU#__d6Q)7PiRzh4|@u|P-FsAO7oO; zQmv&L11yq90F`oF>S6)(eoX4GJ9Kv>-`M<=s`?k&S@Z*Dd!SA*oMER!Hz6b|3I7;78zC~xrog|Ez z;9foQCYyU8f|`aE9V%xu2^>%HG1nuZHsMcnBCo)`QaIw|KdFb$=t44>&nK)i++&be z6S!p-kNlW6n`m+vB3B`6p281^+cP!TYBSp((hEv?62!Z=8#-@uzV1lR&(!)!)m)Vo zvBJ-_dmAOB{kR65BNZ+YM1iQK^F-1l|6)NU+fz-yMx<-WMs1t=2Z_-MHEk0e*SIxA%uHSBEC1@pkI(PQA(NyS?f!Gfy z$=dSOz&{V*SbXkaBtfL~_)|ZEjh3J7Qt3~Xd`C&4`Z?5BnqT`+Jz3o=T;rCEi-_qZ zzrC5m*#UG<$L48E_+ZXvJjXKRJPAo?k5waR{i!X;0L zKl%I)as#!<+-gR)`FvrE)GBWj?W+T-x9U@4NWUU&dK}PK-bd6rJIYHi5i{O{98TTT zy8gVYHJ`P}goO^cBfQz9^%?GI8Xnw-AtM;I6qn%b#<+64 z3Ks158OS6o(U;1#=fmVl-knd;9X$K!?qwdsjI)O>fck)nYhiZrHof_H2C*()k#(xm={m^$U?P%{OM#3*6>?OaB>0P&cyZ<4ymNhC9-;2A2uo!JDG>r2j+;W-K8!8?372Tl>S`j1zg&i5hl)b`|6)YjS^ z+|G|F?&C*q7ps^;TH~HeH}LDj3>(89SC>$3Y40Ge|L+ZrY#o zp+&(zC`^16KfDVIWTW~dUELNgib40i*$ck1T9-IdS}q9n*MG3eo>M$9%C zf(46;`VTjBF}d`R{-p#3r8LNC6}US6UJ`&c61vGS{syQACgJ(bsxRjq$F@~u-%EMm zovmgA1pibsr0V@b5Ft~Vr8IsA;# zTbgy!!;G}_qSDF$!-D=G0A<`|+lEYFqtx`vYm>8jhdcTCQni@GwF>ce0croh!P-53{ehdX z=f?pEk)yB{*Zmwx|MDXP?Q<7U%GYw+LOD7_Z*Oq%-{CgQja{N&y;eWSjnC$a;D%xd z8HI2m5%H+{)_}mTD!C!g^XJFUQhUo`(h;Lr3EfWDx@T!JGpc$?c{FMmqoGKYsGqGG zBVcS?aazu-tmsGRB!t-5)FX1^r6J+XCBV?cecqDT=;XmRjF6OR|9-wE*Iqs|4y5Xm zlOi4{2Hd3`Lx20qW#1_ED-RVEPTA#LThE8@2R(Bj z>ejv1^;^kR_r~G{pAER(^6!}U`m>j@B`-81_M!Q;Nq1u1;6M2A0`Kxy(NC)agHcgG zK8V3U?Gd*No`OmHaO`q|M|s72DU-)o^!v9jZ9A*A*H%XYu$bK8OXZjy-;^VrIHS*? zI1Jw>HbCl`clZNrseay6{DI)y4e*oQ{l-6I4g30t8=XemOuE9tDga~2K?5d07>L3v zMp~K+p;Zz!(8>Gr%J6oR`Is+zjG=cV9 zL*b{}h`!&CNPT{QAUlh+#ah9CJUZ!|XSSIDWd5uYz4wE0y_746{YgB)u(flLeI^1m zTsJz?8$US=SXwNGzta-S@W*Q~G8^BI*P^`Id zDw@mbEKLw@b1nzN4|KJK|7q08T)Gyrj4A$PK!EY+1>PWQ=2yz*dOJDs}$X9fLqqbzu7_4{?i7?j0WTzqC!{(zGDfhW#PiDAFC z=>V*~*-i_P+>?|>-f`&LoleqJvHt`eEYEOVRYaYdXnZRUD1&8fL?YWgpneizseUZZ z-W#|0qZO_wd23*7;mp?Q5o7aqjEUdM`Jw7A(-N+3-tD`81gO`Tf%MBSY{PQjQ)vDP z%{p98$vpKo3wlLMvuAN;cs7;R?KZ?UM&pQ#qredEsX+`9%3~r`8!oVXNm&cXaF&8P zuf3mCUJgxwgH9X|Mhq}f!BlP|#A=hp@EuYD+NE6{9WEn+$9AjWc66$?ZlpVJ$G(#@ z)15Xqw$5o|&{w?59BvpW;lv}!%qw@gHAiK<8j>4yRk|&IydTJQF1Xr{A>lvW8d%;>z4VgW z6rd|#j)Iava=CFX;6mrbP5-EL(GqZHckrzMz=1fcLD7>4we&~Ijv9)J?$-Efbdul~KFZ_xbr*)nn>_o$Odr zYIG+Wp??&HjO(i>#OM!u^TGJ^ern?Ai6(kRGL^|#o2X>#=nuKvy@bQOTL}k+5>WDe zXFI#zudWd-dW$lh@Cdjsx=z@A?`!*E7}>S~JLnQw0yP~)rvLP&(Jb0AqRY5 zU9Fe#^z0Vt+z-jiscw31-S(ndNU zCEFCXC^y!gx>JipL#uza2vD*QGhZxY$*!%FESaA+BD_PY9J3heaLOCcD}0-(n5h&B z9hW(l52P{jjr!(p_{6(TX4gcEutPTkUbBIVC=F=HVBCTuP&l7VoZ>= z_DlG^3!Lg|MvCr0w?PU!ZqVworJ+DtjXYCtap!C%;3;rrG4Cu~F2?cewgwPX#YT4% z+O0#Vw536!8ttg%^wW;l)BFMV@>Y+kucVTGe;4h18(jKQgH)YQtAtFBrtm_lh`k~l z<$B~8o|}YkXo)NcoG|LV?nIDJCw?h>S0N3YJ!~bj$2X#So_8OH1M?0-xWVS6-9tTj zUDuDaU3N(fIe-gg>5pC92tZ9xf9|ENGHn|~V|iC?l5AY6F%=bB16{>=;effx%7_=4S#8-Op(IZ_jWmLf`Qi_v}CvZKM54|WSNJ8(N6 z^*r+hT$NCMmHq13(Ub3uNK$v=f*E;Ok`zm-&ifs6nHVq4E|tq08j%A0#G97MA+Ljc z9|OQ!fwTy5L^|NW2I={U?T(-oBn>2gT%GKD{IJmGYsT8*mZy|PESAO!z7Xm!G`bzZ z2IQl%KuNjZhsaghUk1iL7~Nb9fs8v<_I|Pj)ZUvh*SjG0&NF)Z|Bb{CK;hNxZva0e z+23WB{yS|PxIbt#a3{A{P&2&K!7O||*1*_D3?NwQN;Z59*9lKyoP;BM(1Sl!qXJlm zpa?_mjZc4usSQ1cT6P>qfI^QnM@Dwrq28HJ2ufI>9wHEgN07HY?*y4%U*1^S;@jF2BLo@GeA8R9TWRV6eI{L@#=nQ6GmkZRpPvCRqLeA#Hpx4hr!3_=s zoM4@;H3O0|I%8D}Y)==W53VDaL5A?GviU*B7j1&p*fHtSSx`Fs=aDg8K|GMCvUmfZ z=LxQPqzrLJ;5gwiUG$3h?m=eIw`12dMU=r+IHC>TFnowz74Rbv5VIv{W=Y;#xsz+u zLmDhjH5dcd`oh#Zr&RD9ZYrs-AAf`KGjia;w7?4^za90A4-yFOcC+u!J<P2o?YuS=l;lYTz7`+i6tT;~2V~5o2!%n{}@}?+cI)OVkQ0QNXaacL6 zgnm<^*a;g^iF zK;w{apS};BMmH+oQ6g2uk7|CyF;tJ%Hef*i+(~NP1$;T&ZtaEv`Qp`b4E$`|ynVCl zzsikP#7@X3;5eT&!^sIySwlfeU~Kk}8>i|HG$B08&2H8ETr@d&5iD`e4zUXTRcRVh zu$tk~m$L;S07@`(hB@JdQ31E!_4RdY$;_1GWc9B)zT3d)5AV|f1*?@~h~bB`?S1_i zFAry87H#rH+U!SYk>C&#+8_Ass#C}mAyP_N=3ieESPRTTKR!P0YL{I)5+wH2Tx8$T z+@kDC574#dyzrm5UGqKW_`r2zZU)+HZ=s-a;jqPn~jKmBb;c3T{uti0l}6k8a;_VmNEW zeCJv4V$=qN2I8`8Ii-!r;C6O93Dj5;59&T~Yj*pojfgqeqJ-^%b??;rtW&kXGG31zDo(k{u+;euB*Zvmi5uaXnBP6j z?u+OH#4I$hb<~5t6c7a-G5w=>q_N(}yj!PHQmP1FpWt*!WYS)A`UoOL+ILd$zAm74-mGR|JwFI^zK!Kvn=Pg6I1;1d4tYhnK_xlgWUztsx9EseVU#kc6>4v0 zn?GOEiuRb04UkfB!OpI@3)J+DfTAI5D}p|0=ovg_(;8;JxOeoPl76YX%;x7HRvp!@$VcA4!6^Gmz2KOy8oHNr3jG*p3C!Jze%-ltaxN>N zB#sQIZRqxnC74hFc)@LA)&ptKL?e_#Ej7^E2#v&L1s&~(F}ybMb!Sz4t6~3q|0$f~ zlIPp978LFWYZH`Ha^H%+7j9KTTI~=8R3`DElhHj{1hGi45FS_2Wr|N zOe(WJbam2cZTAzmZM!BBD$JsM37UmMVzO^wr6N{&lE7Ifk*VjR2hM`v+U#3KlTd6h zFeg$DvPzITs-~J9yeQ@RfIDZ$%pH4fmjz@GA@XV->Wopcd6DF-5&!i*&ChZCYC@wU z4y&FVG;|}~Uxvxe6bpL=rrFyHV2uSvwhyA!5f_8Cy1>T-wUPUQnbA8^$}^wjuPcf}6eX>L(&>|HpRy8*C%_ zsI5)|WZnx!Dgw^&{TLe6#WAAQO^Gb+?96h#8FMwQ@E==X4nBrQNFL7)7`ycY$`b3@ zy7RWOqIJYEcuqOtp4mV#@D) zS}ognK{v{xecs)?)tD9_yiG-jlr1X;OJ%m&oOK8pi1G3q!UgjMswDw=Vmr>&7MQA4 znn zqemCvL6a%6QduWbGmBXK82#eMv-rF;CkmYoC$Iwp0~@I;yUM>xuYRO4ZRnf#ynGBe zY7AN8Jv+hxhf_d4$sfZ_2kbe9BmU{}Nk82!b`<&$aETlGwV%x)R?~~ka{mu?Z`l>s z^Rx?x2pZgi2X`khcyMvl6R+CJa&gh{F2fzIV(O3 z&L**sDx4D3iS#HXKnr0Nu)6b-Sq^)BIMF!C(Bh!evBUTJ*muiX)=Obxwooo6FMBb3N{d3laX#h6>*d+^gM#!yg{}k!9Mf8P z`1DDJ-9eo#msZABOVRs8bsaN0z0)wc*8{A?Vt;3_0H?)8o;Eo*b;IcGPVyDV4GP1E z@?*Cg?P6N-zc?jR`e^yD+H1|%SsX<^n&%7UtXd~{3VWHi|HhyCeFb#g<#QBDjvIUL z-4e~E2Nd3!3!=)=Wfowh-oIeEIeA2qoz{=f>=)~G&!57{Yi#(k|4;#vSI+-HHeXVW zvprL4b2t1@IW~U(^(cR9QbL@D?+iIdwmU&AnaJ$&LE~Z7KhTx0odeSFqlFo*9&$ev zSLLpKSoh33*X^ysrKJ6tZ`4ym{N;kY+KmucF&yurZN&1|_|A(n6G= zh+V;tx5YX>C%Fk+&P^1uw>~5;@%M!0kYuqZa>%@WK2Jsd42E#|`7n71TEGA9N18Yk z{jbfiD@q17{c!I5pf9*F_j-6SqbPZ!-?`W*3L#yQ2@y%3vKm}ON&>FmtjQF4Gn54I zV#7Y;vAoH+n=J(xIri0}bu#w|T zzmVW}4^Od2Hytl>B1^%nUt0@Y5T3v|wxToVm#e-X4s`|0|zWa+n`QmrhchAf3jVj;NC9uhL zQ$BOs!rsQ}*Szs1#aEs1A%3MxF%)OXdvSRYl_6%2Q?i;bC$UI_s;1YFlG_1W z)3~7qW~o`1J;%^buSy(#U-tHRroG+u=e}eW20CFRR1a^td@9g$`2w$ES4Vqe-P--q z%i?zIc4@l}Qw(XlOkOZ<&;c6igK<~aZzL@6aCS8?(dzCBsKc}VBvSKd`Bl4@^T5<| z!OxV8-E3}$OQM1OPt?MPfW-<^?DN3(+WwOwJ22Vs+V)v_s1&Ho%W@Z2#)pM+(LkCU zIQX-1>SALblTlbMN0(K6pw&F0b{Y1AW@?%5OA+60{)#jV;b zsZb!A-DEQ|S=h`L9NyV3y0sf@;xjsr2oHuk*$zI-_|gtM8&aY`FsCAQ=O{kr7koQ8 z9(29C3qL8*xd8kOO^Y~NK?c2w20za6`;&KM#J#+ga9r{;Y5*4Hll|p)>2;>!^m)`g zl*bKNyMIrkB76H{8|h51{qqN}Gx6BTaa*&?JoQ6fNrVgirs)jrOZu~svZtmb7`^Y# z;tcws1ur@B1j27tTPOexT;p<|dYPkCApvV;e<$pZiS=;SmzBy|vrD&**r&P|u(0Ac zE>_QD?X~#d^YbD_h>&mnZNxVeXx}l2rY!lX?$}g6tXmy;adRONpvv*5)Y~kzUO;3$ zw-&5jGzXM;q|OQ$H2L$!*RuB+WL6ojXZI!6y$Den@yHwD&i{d9n$37Z4 z7U3MwwW*Qc4inijRv30_hBhQS)tJU~ws+!|pby0@$y3kFYvK*o*Z?`4lmV)KYKs~S z_f4Kp8!Hu-q;{T-W##gc_E7J#$j7%IKIKPn)bKWZ3YVlJ4vmia%B0sukags)&TG&8 ztJ^UAc=or3;2IWTp}@yvofnly{0I!A!jqD8O?`boBDv~9s=JYfoU#nH6B8XnXToQd zchlmW{Zp}|$cCec56_GKEII^Nad;*Q|Q2jlZNOH+U7CT}f}Gdm9=A~{MzjZ&738Z6Y) zNcmbbqdve;ijkzLp&6a^9pGqu8hXJq{*Vln2RJXq0_e}yc?4Q0k1mOU7wYeKH0zSI zG+)FOPqh4q0r>H~U{p1JiHTh~r6lDQr75nZf~QK^{UsJp)Pt}Va7Oi|-nKt6B|jWp zrkI7ZGL6h69XAeP2tYOfISE>3jWk-!u5GE+j|se&DokTBVesu2Wq9nvc$v5k%#j4C zGJ+!`Yz^Vb#Ij*qk(+2m2Q0L{lc||4L1*vc$;FU$R5dz<)B*KNoWoS6!J?#~P>wlT zU5ZF4xoTQgag@x#KY+#&1y!k5I~3Yzx2*PI*nevQG=K0F5Rus1{|xNEuNtVJ`s>Qi zf{KI$(lB7A`qiW+ysxI9`BL*Y8}V|5l$S1P^k6wjVs>f-dfbR+#M+*A3h3p+BgqJp zHl^3l%FDILD2dP71P5_XFC40wv6pxL^5uvgUVP3}fa^*X@)qdi%ft9S3CJQq=?M@-b?nS{aYFxCW1ro)42|1^M{&~`(^L3ycMB6 zk`&<;I-yHhZPQDEpW2bCKML3e%Vx67=2G4Z8O2?ckulW|aFSszM8=@X=`tIuy{gl) z#4XXKWn)2GK<2$krDq~I`Q>WX`AT(&=#OZ^03-YN-NFLh-#FQyTPZ!TR?rEEb(k!c z$|NMrN!}u}Uun|fl9NVNh%9Fp%bCcM_i1}fNT=u+x^e8;(kc?hMix2Rm8%ERYZmH6 zDyqsT*c1M;dum=Go#kIth9Fb$SkMk$QRQ6#5ze)E^eI|0uHCvo7IY;pGM5^24PuKBLw1 z%#(c%o0B>T3U>Of>rx%XN%wi&#yok7xZSvV%?RPh@8wOyx@UO`dMA z7?kp9aqe^fPAse^XWo0hNkacp17Ibt3@r91$l6aq^0hGMKMQ#%*?bfT7HZfwe@|cO)a$Ux0OTM`=ZHQv0-joXTskG=sq?%Z z!;;@+EviZT_M|&jYC`wqkR7HTpPim}8O{I#YOtA5Iyjt!qE9|6t&*{8L1w&h$JR%(S1&5Rk5v)Q=PjRcS|wVqp;E}D**Dxu zg64db>Th}VjdM@>|F~xR4Oe$#Q^@@(MZ;xU8T3-Mv}FH`*-+U?U2)65qCCWI3e%c~ zSX@uh%4^oSMLo^mA%9k)_M2SvO{zpXmMz@pb^2`-aa943mM%f(Y@0Q!Y4X(i@qBWu z3^q)ckES$n`?SnqBgAO%WAsb@G{2*VSNJ%V_})qE?aIhX-q_x{=jmtX-@G;EB~k`Quh7vazL4~7Vmxx?yE6D&Edp~bhnl^r=x0~&4%)-GonVTaWaSHI+Q-g z`oKbW^&s`gW>08hKAE@CZ0oEbb3b|6^-zfjF!zu$B^N!-+QOd|$*GHVf1&;Skg{o8 zvJm!S9CoGW8RK+JBa}+u9Q}muyi!#!Skm}Z@^oJ<5`X#_8K|NH8nh8#73@EW*Y`$L zM;YEZT|HVm^*@0Z4%f);St9+jj-`fEob3IlZddx;*iViNje_^DSZ?`0tm?}4%K4>@ zfwejvEb4PL^Cs_+8*TpO^?j&Wcs&{S+(nTHGO}@OeuLSVYEV-Cl*s$N$zFw~CHyHq zh**Jj)HP5DRv8u~U`dJ@|K`E6a$T{a-q1c*a&mETxe|}kLjc4+;Tj%?0z`=%!(ZU`6UUd#YoV5PTuT*aT} zc7A#LxggA$H#Xs)O48VT8lk6qH7`{G=o+~^Se>S&i9xV_L8++uP_JpXadq5kubzcY zZ^B)5<9c6-h`Gs!da=R)3B;c5y0fG~pfALDW^BH3vDQ$wavEQ8v|Au3MAZVLRR$CF z`q(hX4yX0uw2-XSN!npHQZP;luaHI`+_eCB+=avZM{0MaJrsyC**;PxqzQ-)b%;8* zJmm?>lC4hfP`9s(MTb*D<0S&IJt6niJpa_NBji2v-maGJ8I3e>7d2NMUA1yMF?Y8&#ssyrb@0 zAGEE%`lMtDHY~6`*9UHB$P#DQ!Da#InYEqNNA#CuHbz#v{QraC{|D;zZ^+LXG79Op zP`1ftRZ4df=78qL#YyEwE$LSo_CD1-Z{yWh!|A;4a~AA=(2G{qHf9MqSPNq3AQG7F z*ZT+@lHkN>wyNcLHtFg=%Kr~=#+z*KBORtxyez4y>TFL+`bp{gF((yq}jQK3S(|De$63N8QN(h*{*?{WH$j<(A0}imhP@E>Nu{%6N23) zzMca9LM9zcHIpsZnE&LKu$r}BJGnML_WWP4FxP6gkMSs_z z3&AKrC?U~n0evgS=K2TufAsnvHkdDh>OoXZU!79Cw3crxcRJcikW+P1X_QQSed+(6 zQd};Vnr>lF!`@&&S7A^FMaHfEcow`E=~vql=nf(XhW4Av3@QA}QvRjf7E|i_IV~P> zMa7LGKy}40JhV4>_{lTP=jlEV1;dv!F2cK`jCq4v#&85oZ-$!O=cyb#Q+$1Xnb6(c zx0CZfb0mWEez@qS#BlJ@43X+A(;j$iu;;xLhhLL<1YTkL++~W_Gudiv6p)(%r~YSN zDWwx(4A^bTceaFJgIuibZCszD;!m^1)GaO}FwGuVj62xQsD{Cdg08 zY!9i4-$KIwg=^6DQu z^r=CdY1Os0txg0#4YaOjH9qWD2Ze~kwq1zKVe{w?!ELObOd=6-Z63YV!s4;;Q>ZYs zZT$RVBsure2t<5wHNSo#4cgolFs2+jFTdVq^a{E!yv%U_pUJpOf z+2{28v1uy1Rm+$soz56MZQ?-${?C61@dE^jfZ3z3ZSx;7@@ULq_;_HtF>#n2r%!;_ z3+g~E+=Y6AV{8`J$40!rPg-;~;z#l6LfsK2!KC31=fr&{&-gz33Gksp<2-_m)plbz z%EFTS|DMbl5PWzn^RrFA}skEg^>AQ*N1z(ZdC2=nBzGoTbYiUfCA=c^6s3|p( zKrQU2^ZX!6V<9+Yf(Z0AWzZp-2y979_p1WQ8I^y71Fio}6656_{&e*7o~?eKkt}4+ zn`PR|)POUA^*(8JM&#yd>E=EuB7Z=t`{Y{$)$z9~H8De%e27j?cC0M7Z2xE3nX#AcKyQ1 zie`aL%%>)EovhXAwVv$NKUcD0A1+>IpRl_G5VV=7u*24#MF)31keWP!9Ud5$W2&R4r^T*qp^s{uTdC=rJydzm zF*^MK5Kux-;+f>dQrc(O{{c zLnZ@tZkxMv3pZKNF=EuUjMocxIvR>31Dt<7u9B8ifk-GtfU4$)*q%Y;4&rN(KQ(Ly z?pTLlaEyrY;8KgR;Pc*1Avjrr=V>g5F#?cWnn!T=pp|<$Jw;Urru}^x!BK5-p8Y9l zlZpu@n?PM1+t;7l&PTGrA$?J(RuJ6X8yOp`NxEVs>*a;j(doTg9NZOOu4OA(I2$c^ ze06n|lyCZ8b4M#-p1AYLavxoI_ChM+E%CRk*GFxQSTjdA4_-HV)O{gUD1{vzF9!$d zN5(ln%DXZl0-3VS&g+-$n_}_lrhXLE)GPyo^jm|$(0rUNPUtRtYkQl1j6uD6v9^#g zRK0X}?c`CT#@tL2BP)BC=I$?UC$UL>p&0Sic1J<|-+>IgV}+3K>2j1aq}MSQ|< z&$^VhRJ(O_kfwfg=c_=U-4XqtlmT-PGSvWqMuE+{w~hQJ9`3o|Jdr!M^2VGMzs@8# z!?wqh=rUoOana)cEJpX-Y%fb#gpo8ZGjG$P5>$Nr$T;S;_i0LNN;azKVk=b1wx2&3 zrn6FlhpguWq^ybh3h^}PP4HB>#w_*uD}S*`2C3#|;1AcPSXVY#lXUWyY(`4DnH1|O zTk9vt!86~=qqlych1t5Y^AYYi>5>yyeaOTDBwbib=8x1XE627}YbGZnt)6HhA%jFnP^2IlcJFU}N)} zdx`rm=81OeJJ>9B-!lYhlapJLw>0y^JirE{7@VHiub&eMjSrgGFy(R`zV0VBVKiO~jcf1ADt zO-~$GBC1fGeM$Jx`VHUPpl7#hYw0ubIT*6{sj%6B`eg9oR{%W%Sjq~)t}tm#lfg)L zeSX69?HBeup8A3$)#7>5L@;HM*)mE^{Rs^_p~$zMzoOoN^Zc?0X>+XRCLo{4ymOMF z)$!)=l85ejagyutd8JYPY^^mp)!YQ!QEY4Mv)$iM8yORm{L?6Mr9UFUZq>(^HyB29 zcj}(L8S?ELv(}RXiL7bSg)rUJWSE33!LAq_98k`pq6RO0FJVp=3odr?hTx}Dn+mP z+bzMN_06b2orwTFOfu4<_jDJlqDHtvCw+qE?=tS{@-Lm0bgpv>a?}~gWEGuO@@wgC z2jP-U@v%O__|TL6**aBQq9@QZ)>hD29+WMIPfh2=2elb3^E(uQih%{K-{9=rj|V4M zg4^+@MBY`VXxl&5ZSIVC>|e~E3*__q+#`2EHnJQvNLJi{6>?uIvfAHzSFh@W`Kbi% z7Bv1-)mS2Nf@I3M` zS^2j}zQ1n9<_Xwy#6l693kor5Z(5q!Ri@y1bDzx+0aA)JL0DAqm*5wbD_$1M(T%}v z00B7Vw3dm-smK>9TMnyhSw`8n**%fw`1Xq}v`8=sHK%OG!B(6Zgk7Wr5k|PzJJ2wa zh1VXK_Uaj~6>l)EKeWh;MH8{y8kw86r~|JE*#@vpS6mB`)=p4^jQh$o>ze-h=dJs5 z^o@pnYBvO#Tv0wkAmfR*aL9Of5xC7cS5|)&y_a2bJxqX)ZV%lw?MabiJinW%$t&Is zj`SR173J=5g6XzAg1cK}3%xrPMlc>KR^P)nASqr>!oc&5z*d!WlV|2jUy`#mG)4{% zlkkrFBhiml!ftzI1m_0b*8zG4D?`Gi_I~|S!FWRH zZV=oH|Ex@->`&=K;Fl@7+EfR*&_9c+n@H@zO@B;*7x8SeyYBrBQy;J}4tOVbcQ)Wz ziUR6u)CC=~PHDpojmbHT`_EH^{jvP~T=fh+(ctV>*ZP+^7Wj~H#q31Zuj+T7 zhBi&Cr7zpP7dgbsvkh$V6P8`={lO>#crnc@7P{suujoiO<)B*!1S?d94V&Ff7m38u z{SB&UQgRa!aNd;4Pa1oM%nrze0k=D_Va>`Lmel+%n?2xf;z73ewL><<_q@G{1XHc` zU_mgMdyLJKwk?ZrlgI{C=fBXeypEmVRvMoR4m!=cI`8{H1em zVofSnUg%eXMT1n%m$tuE9tQ0obfJFcVAq_(6h4}>HQGTB^G^xqgR?=xQ-)qRP$!$;*w2!?t@cdEoCvHUySNbE=D9JxF*dCq zQmo1ru_rx$zPDUHe-1tm{JxOrdKJnDhk+spp8p=%eessbQF}h7{jAm?lM!Sin`K0C z(3*Dzheleb-yFWYpR1IhZM!Ft?T;or5^)kPlDXLZ!4RNV!!~JnZ*kUUS#;8uvCxQF z*@jsdJfD@~ARNa^lIY=yu>jLg@e}Q`wmVlPc&_21D0N8!-#6uaTyM*Lw^EH_t+-%* zi#uyUGCmgM$z)pkD%apo>GErTUlo%n@hg>Lc6&|flE}@6lSXGn{dG|x+$ru93?}y+o9N2O% zh0gm0sl@x7H~WAKJZ!mZmz`czo#i~9CtujdjXu=o`>jX3Va<_`ja!AAqb; z>sA;goEwj{cxQSl>ALq^i=gB>>RGkMpbTkuGy!VwJ2)Bdgm&E6Qi_%g0aeC*q!7^u zlLT2Rs<_o5Omd;XulNwJn(32YH|qK8oq5(+!vOEakbE%buB$q^_nK2i(?BKwC~?I& zywx`K-5A`c4s$@EsM$CgHiqZM=C($;Qdosj*v=EF@qDKO&Mb$0L1hnxwnfltF>v;J zL6E%KAtU`VI?L5$1`Sl0qxF~G0(b9R2OuL(kK~c z!N-#^75ckmBIkBW!qr zg%#B4UG%h-+uq{RrA12lhKgYUt-nSXyB2%VVm zqE3^M_mjUM#KX&rJs>8-SAqwH6oU-N{+vbuh)q1GC*0Ym90XFH2M2?a5jR|{MmmkB zRx*(xhXRO0CY;vnSV3{5g7LxdlUGOj#M_srt6pj2fq|S?oA3ZAR?IbaIq#?{exn~d z9pl+wtYa`lxYM{#23N{X{e{FQ$z`!Zj5p&8!?egZ)QbT(KwhsW`$s#z!^k#Z>W?jl z98Xi#^6pfN(E?P>pI%zCJMK1r+nAa$Rsf*^^bXrZELj$`tv<|=zhN87&PJit5iVP^ zA>(|{)8dDXJE)hVqeX{3K5+6}ad;ws@*?og;zhfS=RwGv6TtKA^@o^1<Vb_PD7)@Ql{>=L=l1_%M=~&8y5Lu~-5%4vm(4xyuubSWZ+V|&$1l3Nfj%mS7}OGYpm-QMA!Jem z)TsSUGAw#m{Q_C6c-zAB)i(PNsZ6nseE9P7RM-~+3w>psJC(4{Zz+T{u?84$LK*_~ ze{~T2u>l6{k1doAv{qIg$Pm6XCEwjmKsUE63~NkyCng)-h_TH+;2TGJyQl30f4-Lk z2m!{OY@l4(oZU<=cwjWQ(EI$LEJhH!Nkc3g2BwWBW*zK?J&N^*$A2I9K3$ZwBimgDU$xG+;3FO+EBHdS1r9>jOEet_x64s|}wReMuC-JSLKjA8(Y zD|f%2C<=Y}rE+ADtKU3Nb_AK$&T|j@m$CZ_R0QreY5i;cKCpQYS#NT?*rH}b7(z`q zQ4>Yb0t(3K&T+{r&5AZ>-Fdio9H{YShsvhmW*_plU zFVPxDt2SU8o%}8jJXSovv_!$M;ZY_R)UMaGEak3eO%||J zVJX#_Q?queraVESTd_16IDbVa?!D+J7AwYD@r>ud-i%-EFJ!7I8DC>QuJHJnHqBuZ zml-pzuwBXHHnxyiD1lbZSAobH{-%2#H9tL&{jyw7q|vA;<#+q8?{w9G68&IGzc1Qa zciNF_#C@m3u7K00yJz_AgBwkIcgN&35v-!ArS~V?`)ln%AU zV5v=ZjA1SOF9Uvw$R!W4TQ9X8rgQY24DvZ*lJO-&PShMl#Dwb04nAdp?7SNA-FX!11qqV`V z?-3v7IDy4XI4h6i=&yU?fJGPjSs|{Xs2!EzZR=;>bE-)}T(_@zrU4^g;?f%&lvQYi zj;Y&XJ?3rj?+I6-yC* zLkn+3AEsp2MuYwhjQi2pw$a-GkGBd)dhFgw+nZg&i@P3BQs#2|LzUdALe5j0!6DH# z6%g=wg1>}gNl|g`)!HJPIjC6Jif+BHcjfzYFWTD0TJKz3guMI$a5RutymCpx%IXDc znsW-}%`kO@UWXq_pIiViAM+07RZ&@7>p?{2yu{9Y+&iARNdFupV1c7SXLR8ws-!!v zMEYyun(=$2sPwz~pp#ifW0J=0rPe^$3yd^?>n0z+;anW8-ij{{yXZNxib$zkt$RI1 zx^y7-Gm#;i0Pt9rfH|QMVAY)&NNlNqF4T+M-cOe}G-#Q(79CH!ZO){cMkYuJMZK9_ z;;h|S+V{5-i8s5qQOZ%vkR2wbfwp0ba{@<>-JPe>_r}jEnnZsZ%UuPkw)wlN$htGS zFFEs`!Kyhbp1qcwh5`jh(%Dz@4PdrW*Hk6b#X;+fHz&L~m4;q!S9>H~`TP;RujJg% z^X&N`rhF}XfKR& zy|LK4QxoIJSpXZoMI|Qnqy0VIigP-d)s$9<@bkgK2rg{a8|d|psp9!l9GO5q5At;| zD=V4cjN!iGhdNmYV%lbmZKqD>KwUUWF#N^$?|f1Kzngbq=tPCCy`X&4YU!L(Iqs?f z@kh0zq1fCT+Cr4ulFv~*f1Cx93JZ2NNSEu)aPkSD(aut`v+eGdV(c0yhO?MVu(y>l z#CxV;tXyuVzBHYciZmjfdVn6)Sd*7a{#=oRWH=Frc zxUtf%8PsN!d0Z}OX@+P0QMs+6Y7x-Cwz3y98Q1i{$UT6 zX!vcKdO+)>5P4VZU&+FE24$~2(JeX}S+JAx63Hx)`gaJ0hSThBhGFeuXml1$E}dd& zb-8v|n~QrJv~;`^TbN9CHY|!39WW7s!%2Rcvt)N34c4g)%JsSKh}HHK-N|17lRsNR z;~j_nuD#aoDa`V{aY%so%bh@y-~4Ucf6azBFuaxXcIAA|mIn_er^o>(gO`O!17vYV zVs%u8{)|m66ul=6;(fu8hbm65?A)c}Ak{PfX*eI2*WJ>J@b1AGd*?}l)U^5e)|cye zTAw_?)PCgf+Pz@x?wOXnc>R$8*}QXo;I-;En*7joMpNOhlWCUH;}_~7cm8v`g5G_} z!rTmR;O|2zI1Fo75e|^;2Ta_3_qW3oj6NwirF#$E$98n& zI(oT@(UnrI9!DZRwQ!c6(|%T*d*D6Tn%u9eng{5grDY@$wjsqIo;E|=l*MNJP_dZ< z9%$8fB<3*6@ufPqEgmFHGk9GywnHioAIuk`^4>3`q0;){imPIlEwcRvop3vZhH3`Z zf9Y61Vg)hfS-ut*4H`68RUj5)DvNqD%~L}4z>PL(_j<*~UU_-l&eXZasOERI-V){3 zdFa9s+HzrsAQH+@A#-~CX{Fz)TtU2X9e>(h=MJX)_D%BQ@^WyW&h&?CCVzalGM4;I?1$O0d75J1Xa@PV(E*eRQjNDtQ z#YgaXf2tz>24BwxuR#fl@wRFcDys}#y=sPgH^MrHq4GGN0rNiyxfSjOn^rU946)q> zI4JXXOVQ%+o2tNGTg*A+MuH@+a#PWiK7F|=*-cx-lu8d_$q(xaAM@R^U$svGuMJ+T z=8`W3uH_GxC@G`2hsLbic;%sO&vtUf=evTeqfrq2oqdhpAL zH^n%FkZ7d!P_QBDwe6_`WvJ@g!@G{%7;B5%!)lIr#*$C?iul z^OY{O_}dt&+(y_D?r`Nit+YXjWT-SCZnV=WNv0H`$W_gjV+_HF?K|-g=}27$#f5# z!*Z`%pzfv`$+4bm$1#Z|IYtHli|6LurYvJq{6WbBel>PuVjh4~VfvXASw|?)*_P<~PD+jBk{oyCXsa7#3|?B*hoX&@>SxxYo$`&F*kR*tQ_S zXN6|eDoou+-S@`IoU86t{|=J>v(UG0U+xl64l;D4&~;o0<+l2>`pV@f0Y8wxO6qPB$@l2`rxrD)2B;MTAErhR(%>8|`x`shibT7Z60&HBqONHgysdJyyA zPzl{YEi{CLGSWAE=l&oE;M!Bo}NKbib99rD`WJbpeKc?_tF^n zji0jZSmWj0&&ev7_Wc+E)x0QLrGq`JsJZ|{<7nP4e+SXWF8yjgQAI` z-=C;%i$K9(o-0$bOenU%5Ntdt=$!rM)UYv=K@9;F@u*yZq+&+*S%8-L>Ho+@Q+*X5 zjSvWfvkhnc5rgvr~f#Lh{L~ly0=~q+@LH* za7w17Jx%c!&K)R^bL{_AD8f$DyQFrEikr77%WAy-eUL(Y6v2*z3G9juhV2GM6SCi~ z$Yd+}?ou)V|My&6u_)$rBmLB-r=R+-C7{b}$lkA-pTZF}?@aFN|Gi`X>&RAZnghR?Cud`0`{(+MN3b}&@_QRf^%^pQBNToC>W1Y) z5!Yp2Y}4-S;Q8J#Nzi*@=Q+Hpt-Tx&iPhr&>A2_Z^qzqsFXNpx>zJ z>rzv|MoF}D^SttrYTxsDc^m7L3Veu|N6ST275SH=+vK8cEji?*WmfF?eytWg7)#UE zN?!US$j_L&v;$=>{ZWCit=?B3-sc?OKR-dbej{xYaMDfTQ;tt7=CB6Eq@?gsimP%X z2Ks~;s41>R4$e zA-)mw|Jmu0?EU{Q1;X-~;@!U+ns8K#MSd%5$q`>Lf}kvSECrES@mL9v4hpL{5Bio! z)F=Ht(zlM*y%P!iSP31Ca%Qf@I~(OAoh5qXyq#E6qwWl1kzdk*rV#GdHpjl z{@UtyXyrY_a36mSC!Vg!UK(59kVW8uUA{2s9MStu@y1ny2TOcn23qS9I>xdO1gG~B zBH0JC&jf>culVP0N_}=kz;iPbf`wO1oELQ>V3$6K(&cB39iyn-X1$zj#j=L?C0Kd! z{$`qsbr@dPncc7osNxb z9s2j8#_yIZF-}+Sw&b!4ixkO5Kc-U~BsQWabB}BNq5#?PB_#Pw?6baODRYP0to zA8k04CeDd86a?hXP^Wcd{jx;X_EqK&xqbM}=bU-u6&6PKCHxWBI6*Xj&No6q3Tjyw zj#=ZBmtwrRtl1zjUM)yY00cFp{ieipGsxpiFz1!Pty?P~oT+|dKl7k9xXls&p7tcL ze7?i^r!v7T^@^v}eanH08zO5w-Em388y;^JHE-Rjx0m_;wwFYfpJM7PG2*Jd1;pc0 zccr&CoE*t{X?zf|EcFx{SySq$Qsn4Ko>?k;x)#p5dL;UUqAHVB^?^Au6F;K%Nx1@= zm1JJmJi!RD>2CTvYp1`O`BOn!R8i*jzGhA~Xb^=9s2=QhOV(Etv~It0?l0mJNs6(y z)ERoV9)bJb#6HuHhlfW#c{y`nk-k5(6OuLBCEYowoj(;h=w{@t>u)qIv@pA0m{I4) zSoa$5_J<>Xac4w>cRI-=@&~o9*0sd__;N?}4)PR0@SB&{=|`S18{WD(*({Vrkh$Yd z_=Qfj%-ZA((P`#dyjNlK=(KESYh9AgHEa-=7l5QWepMd-A1eqObyUL$Q(bliFLe4E#%7BuBdrN7ENJuD0sR8xuG z2P*O`8jowVUMoA7yz|NVp%ZHr5+`DZvmX7)vK1nVxERQowb^U(RC+gR^#f8h$WdPR zb8!v#vYOEgDFfZ&AQuP9Lrp-}6^g8~o=j-Pk{H@2g1d~u3>+;P;j=#H5*1_R7NfH9 z>%JqMXm<^vQ{&)P}W(oL}hm|tF=>&$1K2B-$z z8Hz`^3{UT4xjGH2#hR9+DiC{5mG*Ca2xW{q8TBGx)_ZU`8R7f9qkl01`g%f@R+H7WPTRFc` z2Az91m$$;8E-TEv+jdNn@g=lV58&|vKYi8RFo&N#+6hB$c6XK8QK&$tO=okj*$82% z%Ly*d1vlcqYL-o}RZ(d~L9-RII-mKDra#+Kd5BnD|6zVh3LyVo@2!B39tAvrTT4F z>rk1`hk`^2`*8Ab z->{Xou~WC{arx~JkL*^v1=GoPE21;deU-&T8E$|;Z7u}-1eXPK z=kig|S3~eU_YY?omc^5)94F$)uAPwjRg$APkg0fYAF~t*-vcAo!$vw-_|zsOHH5W( zIKg)A+dAFh#1nheLdeOS)sRNA28Jb%PEA}nd2QC%59-ZYv)1;M$SC4w9*0w+fm8+) z(E-iu{(&Lc9ji{H(ht8gxqSGhOa$arFf4VmWm8}!VueIYK%LK8vxzEsbf0!aXd}%h ze_d?^kMZ=*${7;ZrZ-t*Twltu*WR_Uo{4d!@gB~e3je)B8CQYc0ct!R(HUYhBiCn@ zay)A-9==dJ0(^CZouM*BFhH1jh+N%eLu3!P>%btM0}7)}Y<|MRPlX8+@VAOty3Jm% zMeV!S_PFAH=hi7@3u&hX2UH$uSaB>oHo+nTe%#(qcF33+leJvtU+-%T#d0?~hiZD) zKRLqyOEGT>Be-|k?Ui%5lALJug1`cgz>1aM~(AMmTI*awJM-l?g}eFwr0r}E*v=tN8`>4CaMbc4}p zJJ&nbOpm_$iUgcewHBsV`bnHjMlGQPCvK2$gY{8QAkOGbziD46uuXtu09stn^jw{g zvFC+fo%(zvc#AWTZ}aysA5}Tl%3xkL*7I!ynQq5@HxJazKSxLOS913d&K;%DNDoV+ zzS{$3giS-i_Dr!6_VvN)Ss?(ATFnMsNxLIA&waja_+D?elZFb+I#Ig6T65sTH(+FD zwtjVE+z^p*^LA>P)2gpdi_WN_P@?}VCt6{sDp={bAy>)nd)^ji;OM3u-A{B+f3Q`T zeSM-s!I?JmN_Z!@y593y6M@E|To*xe zq5N+uzDS$Uf~1!oYNq6KoeW3YWd>BF;%^<5xyAHdcGF;e!gl* zAmGGKQ$Okx3Cxo|jUpXLFqd6EJtNY{2)-+^=r{3sZDOvt;PMW|p)|nSs$(6M-`SG}iekT#&&nyWf3_V7P`)r1kCH>er)KfCmx-zm|FU4c+tIqi?3cs-F}cPwmqX2>|X%H$R=RO3ro;*&8294zXAl5p?A z&_`<16F-LY%Rl1$as3Re_GvIIh}6^0^hAnc?J7Ta)J$A4o@ETC{$&4zlp>Z&wIQPTSvWG7OO3tm*>(x*}@7`5>D zSr2*k!}EbohPo|yIGTt_ldY7(ikXhM4G_is4twI7tSj;6J5gQ^yauL_HEdR5o%vdu z+xcB#nN!xtUZgTwa@Fh0JN(-Euar_XScb72 z<{-uyg%$>VuwXKRFYf4Pa&%DjD1roG8xV){gtk$64&jIw05QItg~IJCYH0GHbC&DwIL zwRkQ_>iemU%NF#S?9c_9LD{x;#l4|sJ@EkDH$TxUcPJ>W{}r97ykwu&VX*(G zC#_Ko)+VHYVsy<;lA%m4zf^u`3Wa$7HqO4m@LH@HtF`^Pex)sXs!3Vbpd%9Hr+#tG zH&DwbX~BLA_-*4~tQu02Zce|JvxO~|fSJrQ^V0&$@bW!Oq*~`nnvZ%N&do`4p=5(n zqxC|R67l2wPXkiE#uLRSt}ct^Vp?0hyZE;u_d5N`<>nK`i30J0PK)4U z^|9!SXoV@v#CL668Xa3x(~{w9z0TZUKcaw_*9UHsNq)tVE#8f8UCb%zJho37!raGx zOW8j zSUhaiM);XLl5p=)nQzlK-1;%oF#H(i1{8I5I&eJel1_b8$kw4GF2(FH$06J8?4ByA6nd$ zsg2r5fNj?G`+KHH0_JOR8>K70+4|;x^px7XURK(y*{4oghSl}&sI8Bi@kY(EX{Mzs zFVnDF&aJW^o!%irKdbctDgJ@oW^Kirq$Or-PPY1_=EN zfyS>eaqbnq3c{OWlGHWkqlMVmEmC%3qY9q;cyRw=Nu$X^@JBPfRt`CZ5;2Zqmr26BR_40W{!`jI_0ZcBm?d zzzs#0UQ@5(r|(-S&ujgG!|aj+<0j_r783-hq&RLh(k*n%!5^QTpYM5%lM)@W=7Lw* zQNnRBXt*i{D|g}l{Q0z@hqOBy^1K3i_eE=AX|m zDRQn>V>)(?&+Oto0;-oLSVzy8GyFh}He4j+BS~jN(A?{iH%=)I9WGJGn1t%~vl3p5 zRs-cG?hPrjmfFabBD?q<4gGrn&T6rq5Ze8g(ps5VrX%SPoS>DijaZObd;Q4Ur-3XD zv(eNr2XLrYRePOH3UW0hpNuYEbcvqT>r^N(h{fq(&$Azc6V=~v8j==(0qLQ{LBxFq zzJCx-+CGL3!Jl8FsvGSq;O#Dq!vAnpwNJeDq)o2Di`s7*F;;vnV5KgUVWB5{cUdmu ze^Kj(N|0h78^lY+Fr8LyhA?ZBh>I$KtJ3a)Nu*2y5L*jv%ymSmt|}A(^8sZ-qOLMk zn|B3t;w)z3= z%t|EOLAPkbCV5LK$o3PT+WNYWi42IytbSkqKx7>KZJ~?9HS~3`9^S-4&6{KHP@BJz z%S`%riu7~cSEl1w9111E4H4Xfq1FSlhx$H==CgH$5*GT)fm<}OJLWvi6szaf=>Wr` zliJ@Fc!R`6nh*5R`iGP2XV`RLOOh5!=J|tN1Z_mP-!C5)eb1eNq+z5dIQyfXwCUxp^l=Td1oT;4OKW@Yy@aXlX**}%#{P`S z!zW6fF9cB>a5}L}->J2G@IFpCAJi@otb!ONPXh?i72jmx0P0n@64g>9#S^`McHJvso+{h={#n%P(;9#F zLBVppvyzc+Y)0%&zGZURVo;YfDtqID7LpU0Ab!CZQckgtWqW?k0=P#saLxOs&oitR-IT{TbZj z)z_WYs!aEvx=XNF439-f88cBYb4DKYoCX{@(n^@s$lP?el3uw7jWrgm3cHIWxRqSQ z2cQ@=*OL0kc{>s@;I*kYX6m}X_@ zSJ8Qs<7|so7~P6j{n*y9IS#wlm9xG;aT?x+KBzh2YQyiA5e%mVwrqI6yzp-Q&mAoz zGv<6hxNC!?VoEwfQI_^{$B@ys#ewe^!8_a#U7#HH0LQ(XKV9ykz^v1w z*gJB8Y0Ck;5ktXoz7s_ceWcyhl!-wqD#r^T?xwV$L#Y=CQi;TIzN)YVPtg^yG`zEvf;LdRdL^v zT0W1b2kN`I#}a}M>I2iejds`_zGAI@M{KIH@b^H0K%?L?)Ka3X6NC<~>Y=&a_X#aE zj>j%Pe&Zw&5C{K^^_+PV#mTS!a_9pn zIm{b9*>wAfA1kgm^BJ2op|=b`B5#x1?RhURlTCoqMrM<^UxaD4l5h z34ZJXxZxeFXZ&%p@w3ty@2Kqsp4mENPY6yEe70*IjRE1UWn5T{jN@^B=HcGSUCE*` zRr|!_37oi-U@qA`X-isSsB&EG3Y#r8?Pnq0jqkBolpQ%Q<$qP>lZoqJ7`P^xh~Akc z!DX!C+QnubC#MWBl)mUJR}3q@alhMN8$PYQ^iDn{HX|5iVUPHcWT#!-WPTFy5AQGN z@-WZ`rD4+wnb7@-B9qJo)vj)19=7Gfrap4i-od_aW7#?Z?%Wg03q}`%rt#1a)$GQ8 zUJ`W$BQbC7R+`0>YgUP1Id3jxy^;C!o%CJn_BX&pG4ctxb1TeZfh_mvPMpW_k_|Pn zfVXQQr>SDuaW4|2NIhsxN-NgbUb!sG-AoGFG&(@PCWZ0XZuBE2%)WJ?)o~UQ?DS38 za6746KNR^E_znq`XWM*$k6Zb@cs0h&mt?aouABW@kWO{)ka zCbSXZv#}-R!v09m;Yo=VBJ!GV%1gj)^E5bNi?P7M5C4-{{MXt|vFCzPGSgLzY+jFF z-?Mqt6(q0AzFz2nfOCG2pAhuQvC848e4aYx;a7JJ&s$ns!M&izGVQOZw0`O|dPD0S zJ~NXYa(HwUm&3R`=nc{e0@GYMHQgd(LwbA*Z9G$-I=v4_z$H7Fqn@MwkQL+ZOMuPQ zqT^oY{`jzA8RVJ!<5~?sjy)zWam^i^R3Id1n>!YR-|CG%1y@O}bi8NO`BbkQVU~G& zkv95HDF$3Jhe4{wV<8xaV%t7nrs(h2e7DFomMNx|;O+S8ZC*_7KK>y!$OSLy~>O$!y7p}|Hq_(mXUA8f?}ptrX1XoE zX+qk->aX;{4=j@H79Y{Xx-Pk!6xHjx{N|nyqOK;5x_(8&29=>r4CZl<@`{IWi+2~Y zvCk1IIL{C?xn6$Od9rvq8T2!b)%|+e$-kqo@fk_C`}juLMrtM0uw?l+)k3&oOkvzakY=RCy!1h``TI(I`G;e7EN)%jpXt(8g*{w>*EAt7Y8 zC6&xnTrZtWYp%zBYR#N9Igy(z3BEL3$+8(7dp(=*BQG`?+s$|!%i410t2<9ZWb1hv zWUI1Su+i^e0YeV}ro3Fd&1(4V<%(g&Yl_TQO;L_ zi&^90Hf|>Ln5G*8jWMNh77$P453oU+%>u5AmF|f`3~#1j6Tayrh#u`-%EL3E^9I0R zm;F@tg5tAdjsY10xqdCrSNf%d_h5nAwG$b!!sT+Xw$cnu^^q$ggj)~Da7ph!>0CW3 z|Lh0_5Lo_P3P2(|`$;c=ZyD*?=qw%g-t+1Ag?%y?RsxV3>^ZXdC6&DKVXX)Z2srpB zUUZezO(>1MXWVkmpesk|vRoGJ3o_bYQeu+>im~irLBSGU(Fo_E4*F^AnzR-}Aj2#4 ziy548=3*K4xV%?Da2s@}Qu^f3OJnzodg) z4lYCu?cgn%t*9p<@ZL4F{!KHy1CP}(*r&(tUDaUQj-ptEv!oLA9R2SeS!)mH|1&^R z2^x~5kJNrEId<7-vq^28*|^L!oSQaC=DOo$)Do_l<2;o0m(2LT(27I|G=w!1nXobS zrDH2t<#y{br^N!4u_M`&?7M5!60iCFG?M$>-q?AOBvWo{4lupEk@B zQSGKTO1ZV&ihlRYujkFvzWi$$?bArqi9ha@L=32U6#4HB{-5`Z4avlN1`Z>y%~vbd z;9^WtAQ^r-Sf|>4=dT*TJWbnwF7IP_n~h|z^>4-hHoK(Ve>X(30Nr%avVgxT)V+5V zGE|Q?UZv|&B-#a9tjU5tPH19Qd;a7(o1c459mo6ykp9~L{@=#?-#;Ts{|LtAuwCB{ z8Em`$#(mPi!n&~10U?7!C7M#@^Et%ROwFn`XXlZyOlette84vOf+NEQ60eP)_c_VzTODS#E5^KF*h3pM*uCe8e4Q+X*b|m7sBsGPZw08eU zNK$I1lAKd!yJX~+r>gZE1||sr-Zf;WMJC$6(k_0-9X(J#nE^b3AF`t}I6NpDlK~m@ zyeYpqTB%m97F>Zc7s(`dbp<8kPgDY(ut5iPm~WEu9c_{dKA>*vstbI4zP7ly8Oh@% zOKR~&BaX%{zpm8c*;|Zr{mo=LgMeAW?RA8Xi7CAV`ZDi73WR94j;D{rf#P;_da7KP z9nDTRtF~g*!O&05iIm>(NbP+wS?I?v1;6**ZADfh+m*|!Z@sz5#xcJ$@K&#dN;Le|1kbW{csn3c0tKcW0YvCqq+jlsozy zpTm!~200wg)hwQpYHuS8i;MFX%;FOgs-fgrkL8D>Bg?-w?Tx}FSCw9Jl+64WPxjZK z-|iLkTFHuL&(nfvtF*kl8DXfT2TYEJ+b33P>)oSyHa%F7eumeD-;&8JdP$BZC1XOh z8|_HRTX&~|gDLUWJ_g;*!1q&-&fInB#>i(?$4#iC%}T@mUI`f?t!t+3iwwFg83me# z+MNjaNBujq596@O$e#&SxbkfNb76zu2MVysDk@HS?{r%2dlmPs7($P=2UcMqoy@fs zeNM5YSIJu~ZD+<8{VD5h#G-2RCZNjZ@4K+xJ0wGv-%nY_oDFM~oFh9;e4#*r{|iiz z+%d`jsNmlkXXzYY%VF{k3k({hc7?yFJ=Qz{Az0gH{`kJrO(%zv1CLb?l`^sjxL(|y z5IJB)+7B=I|LbS=`@G|61tAnjorW7YEQ-J=(XGK41qB5$KxUTS`eNZARWuE24iHH3 zgxXp8ZhJDQpVN9iAU`+73+j&eYhXy=|1vN@cn+4Wp4!a&nB+MWIb0`qQWhM^92b7Y z>nRT8wp`3{v-Rp~e7Egpvn75`vSr)>*73^~cBkv|_LKkN9}g_CJB)W!$l*yE4ewwv z6X9XHDTF#uuvi|8p!8MmK;itFJL)|9ysV;f5}hK_;Liz<)8#^FxA?FBVU&{V8;&+C zF>GVuLRO+^#LaS!u)PXflw*M^&%2Oaj9-RdI8;&qL2i{w*$nso#&P_G;CdZdx%bJGV{?Qw z9y$RT8xuspTas1oBeyE0xcJ|b>_H{fYDG`da6rthzjjCJi&BBN0<=BnE^8x^`-!hGrZ$zfbq&tsLPFa`NS^>G*7kFq>_f?rbqxo>j`JQ*6ffx1`z6Z$Y6bOs+?nIy zu;;BIzr4dW6Oz=2j9~@p*%at#5&N%hTeAoooF?#KM_@^JR5((Ugpr~o2W)2M6dn0+ zu7P16sbihYbYP~3^AGsamKaE5x92 z8PmE|(>?=@Oc)v&alW0@aXSUaRdr$NwVdzWUtq5HxEmeJ)fh%+z>abVU?WfoAqLR& zhg{EiTLk}@;252yNEn1nDhRf_)EOdjV{9SAF7ORxUDQ@w4{EBpT0T2CeQ+fn`7-L8 zprF{IPlPm&nigRAn?d+wRK@dhc&$*A z#57Wjq<|IkqD0Gp)X=-TGl5P#j8#1u`M`-Bv!L%;X_QKRHU8d0gX_Be>R3_6i#URt zEgW^y10&PsGJoP6_S84YgFU-(3jSo*{>*RiaU?C#?dkDA)T-W?E}XSf>qxkiE*ra-8| zkYdZXUpu(UG{qnTPeUBtKeXyV)zL7TV2Pkx!!akrtar7GJxcD%-C1(;+dbun{+mLB z3d2T=tsHaW)!Cn}!n&Z}vJdZ@9_amv$MFxe zTo)6rgvVt}WV`DA({kc=(Ru|qJf%BvzTtfXS-ny5+!~rt!s4TN9&vX4hn?v>k!F<& zisdR##bZ~@3bx#Tzjr-@56H*QeNv(~L#5I6Qi?viqfvG@e5mCSR$>@L?b3Ioyk6l%Z5& zRt|H{-II-8b52y;ukEpz=*-4UJ-$%|WokvYJ{d|T!6(moS$V}21NP(}{=T;qm#Plu z&xU?L)+9?z|NgUYWX5I8;;w0`DMvPD@>1=U&`iJl)0Jb+58odd{j?jiye*9_3A&$% z)43eElKk}ttFPuR1(R}4GqmX9Ha>LaTsOKTQZ8_^KpH+O4`ZHt>G}|iv0ADn3%<4D z7nVeY<{>fvt}}UTJ%6yfMObIqNV-kUWH#ip1g^D5lAH8EN*)l?g}&413D{HIdim|v z%hg^@BG_#%D;1e}G zC)70%g=26M&8gfKio@(+p-s0(T=96~Ce~zsU#o5qNQ99-U}?s7EB5!wxXvjZpF2U* zo7W}LHwNEL@OVkfTxx@6o&%-;gLyd_g=OQvt$lO0(vuTnZGxh@1{*IHR@`|dyOs6L z6;1nYRd!ws@NT+3I2wae38gbQJYil@2i2>)q70vIDy|8}(~#75=FR-C00>tA8&YrP zphl{xg4a&lkF04Ze_no1jZ&O+qb|_S>^~FNDXpxV+%l$51)lmj@v!c`TqzK8MPvtL zP8HL6`#>jhbj5_sMCO6zH(_tcJ44C28%G~uL}D?olCr!NMB{fMxT0vHSfY_Gg_vHb z!6aT<MpBW1T59%aq5ocC6|Y1mN($<9%;!yUwY8w6s8 zqt~-u(G+xC8((~9ZL@ftxGXw+3utD^+k2iGKW7-!{;2UZGTLUQ!Gz_1nyGjno2%sT zN6{7PIKDOA>lE!Wk8FA#(apv?t;@n@F{^Jwt7I`Xw#Akwf2- zHUxNb^KG`?3~c5T1_Z1h>QQA%5*}X|`NXJFK3@>KL6__BjMwl7y6s{UGOYx$TRYmf zHSNQ#bU&@&%rd@rwtoK6he`3}$OM0j=F^+YSKJ-c(D|+_m>pLdg?Zx7%KWw`zlv_l zyDO1aD|~QNS7GKkGkl(ITE+b zI#Zdh*7)qBVG%v{YH@uF~q<;0D?8<;)D!`q>6;H<3D6a zdY(!Mdj@lN*BIwlaBY*@Qpq*-`1#%{MI}-Rts3$^hi^4F>?H2ImYJ&=pKHed<5eJKOZb% z+3723>Wfa5_x{TQERmY!8xpxc_`Lt#vXFd5>Jkh3_TGd5(YH&-kD^b^kWGhuJZtN& zB56j<9fgHtWbf-c9D_O5tq%SM_lP={NPv;ya>6Tb>U;U=3D53o31wW-rPpPPQ%xs3 z>P_osF14!T<;DAap(@?ya*fKAJV^YNG}0$p#sgPEj>0QAOzlTG1U<$=pDD!h$|kf+ zeq(b*@+2|PGA>(P7uxehE>?HlQFL|%6BJ9ztzL3m|%x)ZBRC>HC)2aF*O;_rXqt+N}sga#l8Xt z&$+UYlcd?aN05u+ucskik^77QH+u zBR_5@<@ivyLKC!yIZk>HvELom=cj`!pvzrU+RJq(*yyeB^fh?l_SmgdVk*UJ*7=yn zvg1fTe3L={Q?+7d!6FaE@Q0u_-H{%1G>JgSgFW9{xRT>n92sO(=4O zOjOX?S}|kv+U9JX%k7WeU_NQw*DsvT?k;q7z+!#|+=9L(fht6H#{p|{Jp=Yf)V8fY zi$59|kKO-sa9p7QSMS%?H(2OkRS!8-j#kmOA+dlhi;4cn+?sPE| zpf?cSb?Xkhe$6 zXgv?zQ`BmklCWh8<8VL(bUJ3XGyXN$g%|!^Gnd@vt2nuX!?Y<)BunZ{T) zGTeY1QVt zr!epC>^0d5Rp9tTxC2M~) zW&>o^aH}_Ol0!yP6$_oYjZ*KcOu(0484bGwb^}<)J5&j>uHUSlaAlyA)Q|Hny;FZG zNcq0Lgb8+`o`!{;6Emoh+vX2DI=U*a=uTyIlRtpB1=jE6d0T?3^P6$@knhW!%)UNCsx4z zF*=<%Y@Wvds1SK zn2QHTUBppj_qav7vgfzLuW-#{xZJz!PVfmhJ-31lzIb&S***#Hx-QRJfTXU}uh&wY zzArM3*DqRH3VqhAem7S+*w=*hiFi>Y88>XCjsZB?XLS^}h+?@UKgqW%Kgm_-{yJX} zpMXXYF9?KAZ%&FL(h+Ta65(5%)Tt1p^>>NH`i7f=3D`_XjcHjxpBs4i+!Qar-%9EUQhCy}udT zs$P_x_@z^Un?Sw0B4EPtftJN=X+9(xuj5BA6(u?x?jP4CQhc_lxG8JRt0()cR;=vu zJtjYub}70UM`CSI96;ho24zt|*Nek3R+SoZG?$ueh3aIFgWj0J%m5tP9bt7$CA~UO z06gyqkFn)>xP4-&IZc9_>zt8DtuY)RjVgwQSNJG}j7GCPC}QQ?aygtxAuI<5qaU3$ z_Mq}hAIix%)F(bYe?M82>{XvL!^a3p=kj4>ht!x1FOE&>`-^2P&Y4DppwOT&5hq?JIX^)5vkEz%Y{)jd(A=~d3UvRa<9Gr{&4r% z+qaFVw!M%ZnnMbe^*{amb?&a?X`m}wa)_oR)cpak=w~IGRLo?#+|4fBVli+h%rP(m zK$4Y}MTlrY36*eYUa8f{$Ka47aSBS;MsFJrk)-5LinlH+WME-uf`b?sPan%r^L40} z&w6cc=trhTk@MYKxjWe4!Hnh2NB@}cR^R!ZCet^T2nZW4dHeEb@CezK% zBsr0|r`|MJ%pv7Q0-UuePWIHsxUJFtdF)KBL|QMURa!b7qR_w zJrZMXi;SEi{X+*z?fDOXCsQ0&}=0-?T`>-Yy27+nzq6(-|KHQGNA%;h%P= zctl7@oQoeVE0A7kfP4{k>{qa(p!kgD|8@oB@rr(dL#cD0v9zN#|Hgq&YTH$p45>zO zffc+MX)-ObNcpsey38Q|>g=f09Deq?oWyJFQ}E|%<#X&gcz%hN6KLA}$D%rTmp6Up%nSF%-T6z4>OZ=I=`g_FxppKVRC0j7TgXJ*gT zHAUw;m<4&{uA%LXjurPa*fQh&Tv0`C8;&E{2zbcvIZ7fPm-MbDRL6_rKO`yb`Thv) zy1&LADzLY_^21LxcbEdleRW>+y36N8&@bAQPCGtKEj?d$0AIwce3$yz&LWQ&@zKnpBNg;M52^Gqci3 zC9Tv!cl2uD%ID9)Oq5-AqerGG| z(;E~jka?bS+R*@tz5~ z={_iIVUL36;SHa9avQ6`aT&ub47hB zKWTo~ka0h2ZjK~7pzwyKf`Bh9GB4+yBNf$(?yoh)xBe`Df41u0Qm>sBdf=LUi1-7` z!ijlssEsk#PwgaPp&UMuX?lw34#VE{^dbAj%I_wu67W{c+e8QgXoti^F0G%#?7m2> z8585CUdjiN`!EGFhpowP_d;+2UvtBBW{@LqI;H1|R$9To&MuFg#iyHetK{rHwl#m; zn&^6YjXnA<>KTj(&3mO5(VE^j=^1e3A{RTt@6-}iaa--{ZWyh0nFh1rz>PSaG1#^{ z{^~Gi$rps_ZeiSZlUR@}jz-mDUQDBoee-b~UB7bPjKE@Ya$*a}LT`obX~3Bb|d0 zTK1M%;$*#TyW4PW5gK<_cwLqi9gTq%O#6^1t2iR#+uXR!j*Ga z%Ml$J@C)5l@(H&+ze8HfbeKFxGYi+k$r24^I_?h3yPDAExFO6Ak^N0y(AaJ>~di53p+sTdsLt;&|cVGP|PzpYtizu_@IwJouJ_5+gpzejR3uh{!X@2Yw(jMYN|?pPscx*i zvH1mHpllDW!Q^QoN-;!5bFe0AKVb3?jeRLzaM=i^DBf*tdtSt);R&5-wb~m9d*1q8Dar3Vm&>!&9rR@ov^MCkX zZ6iW*`~#|lL8YgL`X;621Q(ptqx0hY6)q9DmG$)emDB6V2*&n_d(3kK7TNOV;YUw% z<{N1x@%v0!|TrR=& zkG;#;Or}6oPf%xdLm-vs1_(y>vc0OvZ?6kQ!2a=qQO>Z%S#%!NSE!=reb>P=b48WB zClDx5dU+7$qjyd_H1twd!;5Qo%Gs&?VB9P=OWJs#k9K}jBQj6N+22V1K|%LRVa3*r zYoqqe+xhms$_iC<^CDj-9wM%RK&^0o>4zJqUhOt;^H$iCS$Uyx3?_wnz2~@|r4zE_a_*Dku>n zrRhMY-Ue$S9qnYB0RFwgy2+GUwU;Df>^J%08&U{m%{xy%6f(hLYUaO%T%v+>*x#f!SENa_z2U4jgP!8NKRJ zn(tAqg4__i_G-7h*m#QMIEzk8mN)Kh1#ywM$hu2pmFmvyqV|VUpwd7n(AICozSNG= z{MIMFOp$-u*n1|1s-=uhgW^+CnEuuuFft#&$i~i|%j=1ABT#cv`L`)t`_RGud%lEw z08g%)T^%gdWzVfm7;)kH%g)WS@LxiKA7oo@!?b5%bSfWJk&l;c6B|&VXoG)hp`L6{ z?L2qoav-YEQ!s4ohK~BE+~m2tEiUggcS8_%-pT*QBJaB z!&J*&r&E!;jGO{F6KBw3vde$Era&l4VNr2X&g<{7hEj;7rKgcSj3l(TAVvx_yhvMR zCYPwdK{pegn;;lT2?Jqkub0YWX{+wzAa*Pis<8+0@cjFe9sN`-2F>jTtERHI7`c4H zMf+P}y@jE+d?IU4&hAqAqUEixpzaQy6qDzP5^yEj#Zy6Z4JOV7t_Fr*&1dT=QZyu` z*2btynjWkl9Z}(wc|t~hiR*T!{Z-;(|9{EP6R8wT+k0k_EePK``>8!|RHYI!Q}L3< z*VLoMcoe9u7jatikaZ8_RKw*llD*5@~!Lq823W9<0Ml@;8PLp($kpw{ZGyuTJQstnSzL8%D z9FH`7&ackp6sUMi*diNypiGpy&_Z(|$DZivTeJ6_1mr%awHv*CBR`I#xjE+g`3P|J zIM23{`^BqTO}5`wLmA#cc335^py`xY@$sdvZ0S|0a?nSQ{7~CQsXJ;G>J5h`Pye@k zOauzU2Vi~NnCnw?^u#SYpx5vS;%4ZnK|3oa^)HJ*uj#fCiDBv9PAWILc?T7|AIZZy@qfBWG#{ zot2=uE-Aje=GhKxz}cX^~JhJ4Ek@zATxr4iTPadvcA!dwtbRttdWrs_#~BdA@t%g%k|%F5K#gnJDrQJ>YSK10-7R` z*3#N^zh`M0Z~U2~s70`Pt@;X;?bj1>C@pC1kJ=r)cwmAGGfGaAN({e6=4C~jEBFr# zL`$&`_wXP3hv;-EpWr5qF><|}e2F^25+R`{;cZb$pUjUrk6nCl|F~hpM*m1B0eo{; z$*(S_-E?RAZ#&=_sCfMkWV~R85YB!bM^|MraoL%DKGoEH&>No81Xm|sKI136Y*9co z)l#ynL`xQ+8M0)QCu)Cth+*8_m&oopYmZ%L99A@fg>phq!c^?1{>ik*AA-J3@kPxg zsZ+>FKUXBA;FSD#l2L+E$1(L5TAr4r>iulp)i^G6i|7F?#KrX*j)0An| zrrz{g6TAjuAz0Vm@TH1Z-j#8GMiu`v_j%f2iT+7K$6c=dZM`E$T_DJ#dVRS?Ak72x zY!lOR+}nw$SN3OZW|F5PCqCJte_==4{glj}$wIv6#d*nu)TO&r>1A zZv>f1@)zC*LFdY2V`W%e6e3!+51H}mm1{on5~{Idr9>6lznq&2bhMX|VWXv@nhgGJ zu>4+;#48^Wxgr64-j+nBDoyzFMTf@>7!yG#+TF&TbZ-rb=G@4$-M}y|-)c@zpx=yx4mK z(TOx!8NaBBIWE*Fe|^39BhC6a*v@vw#Q^7=>8v*}YAxklih&R}iFl`mnWX1P2g(E9{r1#s;PYx}(CLLtPDiH$PEAiA1Tp!~?=K5Q-)5vccP{yn z5GRUBM7}dngC&1A2IR$v+UnO9qd;3kMruCgZw1DR)IkiiV%<{LF?=FJf}!Jm){ns_ zqPcxLeSo8-Z9e}qWoo^eT`v`S{PBn-JT0--xTzBv?bb`FuZ=OZm}%-A4Y5XM z0HuW&B#7-gX=AU*bCm`}Lq!fDT#5L={#b0)N~6?p943DyftmG?gx{+eBeBR4g(r(_ z*Wjby2IxcW*mdi2T4%a#2TeaDxR@g-sl+FmFdZu&DN}zr+_YU^WDpr*kB#rMu7}T- zx!O+W?mdshY(@*$sXbJ3?W3UReaqv?8o`YUAp`^_LTt zUfWpSvDz~XtUJ+U0v>V3TuU3aPt41jd%fqAYJS7eyE;Y^u8iHee01Yh7Xx4wIpZPy zay4wN<&rtd)0Rk;Y?q0X4zhR#rw~Xdz3Fd_mr2sN?_%D#;QHo94i6)hea{BG1IZmVu^8q#Ac8oF8 z=U*8I!h#*>zhsRrutp!d1SslZ{vmXWo$DDXpni9LER8RGh2w80OHR#@F*X&)>M+TK zQq`?=9{X-G+c~QWk%c`^?@PawzZ=*Lhe`3^FqBY%#5-$Gfyr;+%@^!_@(VkwbR%B0+RU+mg@?zP5QGk%QJ*r+&(@up`aq@-sJ215v@>G zOSvx>?nu)Qu$m|LB@^vCq?igWQWR0|-9E2{5*vo^PD*{G4vsIM+Dn3-@5x6^@hUIj zQ}P$bnGYXijk|SehAAbnnh9qvAc< z#QMt_q&QILQ=%C;bZ>mA$iJ)NxI|W)CT4g_Lq)Pi zLC5?5kF9TvujJddZAP7RY}@7zJGO1xcG9tJJL$M%+uE`1?AXTJ=l;*R@7?#_S|935 z{c2U!nrqgoImaBss6vP?b;@YHlDw?SD1UmyXWu=T=C>llBB#H8yhM+^hstdQctCg;AgPL1zAv(mz56wln>s#2H3)UJzZCHPI4(B2-&n1`np!8NQ`y=u zblxhm8AnK>6J2O|5`n{)BAn{`#jrKoP*RRWvhCYnMlmg>H2ccQI_9-+pfopE&LI%P zm6nJA`0jS~V86E0Az)aKyDm6V13nCdU0)5WkaM!~E4Zp_|H4&IT8;!QVUNBWNpsF8 zJCl;IKK}%$@?tJ=&WEIF3ObPaM24q>)AQ3AL83&^OWa>CKtoAy#bel@1xv({!oOBq z-=ax>1I&H|kl`c1O^oXVsCn{tlz7(-GMe|1M%!YDUO;0*g+(9sCO>AM6aTuc223xHT~b&uJX z`?)Wz>AV@sSHwdK)lTi}d;ed9*KZJT_(2b$(|}f{zaLO4XB}4RQ4~Xvlf?gaK*+5P z*vc#Q9{V0;-dY*LKaxvVX_E)xPMWTjqiiv!CRc0MCF;*(9ld`s2tIEpXeaF^V9wrf ztIpIdvF{U&xj;K)PcT(8Tear4S|+3e_wYXBw4;o+SE+I!TAqn2rmmmi_(DWXLXV#! zbayi7N6P3aOn#CPGIg-F#ORuA9(Yd6yFEu5PO>5<%&mrRLLiiRPV*jG{b7#&rDN&WzpsYzkZF0eLk9v~!v4 z=&mm+9rY;?06JS?dq!`vgALDM(K%QamUNUa{+t$A=OB+_c_8}N!uU(v7325?Qn!u0 zv^0@oJDmf?$~W<}$Ri&=NqvtmO=|`l6$os=cHxw&&)MJM$mj5Hza8PuGNrrDkoJ{64kY)hK9(y_-xPa97O$3}znj92N znI0ao|My-s?8{g1{v6 z@ql7MCd)q!}tBO(y*s}H4-=Nv}$ANOe51r%tP&|G<{I|Gv8E%eWI-}m^9T@+b zcbgAZD$(vhR6@_|6J-2GmJb|CYw2K4C1kcqaN`aBTuJA!lb&qZ)(3E6PLtj!No$uN zJw;rto@&r#Ad64qq4}*y2vM6*-!EjEPaY@Emu*;nd9XmfHTz7{Rv;Cd$-minc-e(A z)}D>N?H|=56&u?c})&18rrvNg3y`8h8y*`0hunYqa(;X8A<8Q z&(%a`Hs$=Cf)cRVFsgCY9USNTgX3bb%@7Rys|KX6C=xt$Cy5{T$J@XOhnyW?b-G#p z-p^QSD7!$}YG5*17#FF5{p)pN{Smk(W7U{F_lLqDenz=G)5&R^I5aGc3vhN3|5~_) z^rWGB4s%LLn1_Lemrq@*8`s>V>z-OQ?6cnj_V!P|6Tyn!4%r#GLqbE0Mwe#1nZ9@_YPTv_zQp|=xFq@lEklT{m z8Ow4&PL@|aQ>yMP{Uwzl%w3+gAIGHv!kIk3LJ=V=0veh8e=&OMj~h)MLsgZe6KW0} zplQt8o$sMtK^BiPy@Fda;lx`;Thc3_t8qZD=ed@B6j2q#+HQ&0#dI zbMzdJwawa;*a9UlI>qi_1Q+d1-W-ahG6w?1yK1(L+<@<~vu#W6LiU#3IPP%`C$jOv zY$a@GJ0=jR1$4FcldQsgKdaXJg^dk{q%M2bt@z4|Uw?2nhh6b1rg1ovjk!YRHwjIr z#QwXvy%UbKkPJ<-0LalnqobpPn;%5rHEM8EjJwu~>XDN1k{}??>Y}Pr=gT*e)O?_w zHg_)VXz~`H*1v+Cq>VxMn_`h_fFfmgva+1Mf!1-9;}7*m<)+*{RJH zn_k|IQrcGREAzWKWI`+gXYWCsjizPdBaBmS^aFAMH+vj$_(!u00w5f?4To zOu1@A%Y|Qew}$3)#jczpUQ0$CQqLz9b52E^@?v2_*Sa;#pzn$_6i zm`%}V7HebqpUv`j#E&lk`j|FPVQwC(t>jgzW0lXcG2viVY2V`E{N}^8oo$`Zu8Ukl z&27r<9~e#7fXVZNGTx?;RbAb&bp^hb>V&p;82?xLy-b{IONFoo0k=Y2g`J+i@mHQr zBS)+M83$<+`d`D;aTUR!9}cKm{dJ{{$#7H;N?lE^-5>a%j+VxJF!j%+7MkA3R@I>y zl%z-79r#fE=u}uj^CWlf$|&a|jYu9}uEx1hfDTV_=$WtlVpFwmSKqW>^g%5GjSat_ z3AvD_`5i}M^?Ed7AjweIqlQB`f@^C}fpGF>Gzc~c#NpQ$6b6%%9mjLWv z4mV8nX(Ke&Hn;uw(dg{yK2~FF@7m_-30Pa7pFH+XYEz8PxU1X8kzDQ-@ZP*z8{OI4 z>e0MlHx8Y26NyUiZoWdsqFcQ6W5 zwh1k&bnhTC!l1)wWhhC;6pxKngy|8Uve=_J1YY9Jh;IJog0{-HMU?lxCS9Q~MGyK1eD?ws?G{+k__ zhO{QC?>{pJ#N5a~GtJ zW;!&3Lazd&Io4?~Ah~^X>Q~YR$wn$6S6dHPB&3Z(DKawS(%i-;fZgiO&6ek4PbZ0q zO`eIPJo)KL+wIHJYKwvGNqAjC$-e@)|GUY?WTq6g*Wm_H&u>4Bc|dWAv?;hOB~^!7 z*AU%iHOf=EN|k7|zq=E!G+BuR1oK^5E@nHKEvGhVYf*rdqGeCmN;G41ZXX+Poy&bg z4bx_n+#Vb?8ZSg9vw6(l47GJ`oO*%NX|>h9GB@{KGYyvPE9}-nNu$+@cOi{V=1*U< ztAHF`R{&a0mpt*i7|IVB>y-veVX$zo`Dz0@F7{$?-=LrDNmH(7Q?}E^Od2P?%HZ@g z;$-dqU+OcdiQt>*&qD{w1xl3Ir&c(RxdTE%5QTdQT~`)0Wi$X2|8Z-UrybJpB&WfJ z8^ggfMA1U#c6sT}vI5?RdqQ2kl2}LCqRxI+9LXiQ$|tpN`!QTi{<6BR#gQF6(K7fm z`O@G>{(-poi)!hOH?_~%N>Wu8m;6H=RU+kC_bNV1o?x5FT-9QvjCR{}i?U*wic8PJ zNPx(M#%u*YaXO2+^rFqW`PI5=Ge`4B!JZa^9sj7Mk8()R4>ZL*EmEA*bqd`oq#_B< z%PY~G8nSoE5W4w2@ZuLrfdgIiq;S-%cq@}0sD>~ z3OJOdy+&3B&L4wba=t8i9#bTu@kIgM(t`GXv;y|u?e&I9XqeEL(<(q8JXMXlwL69J zO6i40ao;#U>sANfw(9-9{h{PUCtUhmfCx(aYI?uhXL5rGDxIxknm(RcI#^F8!xcf+ z{~g(Ex5G412zgNe!mi#u-HGmq`oW4#E2n^+^7zyKURfE4-e?0D!||>W+bK zyBg+(XA_ma{`TocgJ_sKK?Nv2Q}REdI`EO3*5TYpbesK{>7y9BS9Yp1m8WrEcc5`; z>^7@Lhtkz3gWils6k*Isgr%Cl^r6dG6ha99x*#m&`1yRX8dG<^OvXLqn&qTPd)WnO zOGZ2xX}ar-{H?lR!uI$+NjqI(qZ9|<_mUUy!b^zngC>+)Mz};Fv5X5P4z%Jc;JWeT z1LNNdL5I~Zx-Ti$+X=l|eZoMdWw1eETTG)-uJ(6QraT~_fajjA%60f@=Xhy_Q=!wJ zt4OD;cNnlZkO*e3ZZKHL(O@_)7M9-T)kSng7u~3sOMxOdSc1i3U-#expgZsHh{eIo zUjmXouVBMg9*JRYSJ5BO6nsI&8Ix=Ez?LxBPY30h2oV| zuexzF9LW?Cgo{+LuuQ+^7`d$?6bcszdVhb~#A}~-D;B6{cQOlh%o9lb!yfpfR8K61 zkc2yU=?_$IACVe+9$6JIdTGBlGe_eUP-J~dd7=<3FtDkAnv6madd|9G2;|iVY>rIo zb_zge)N&-#1)EM>6@FDssn3@u<}2cDf`1Q0B9+)a+6n{}7@r3wy@^@S1Lb*Iy zHFquU2N$gNJ0zc!{`8Nu_6wEJ(an1WGTi8o>5Sf>h+Vylz=(24I+>q|l!h@85nOc9 z(Mu~UyQj~OmO$Z8y!=ztsvaQ`=wA~}dF-}w1?qz`+6XS02r~bZh65k_XNeANvJDs@pUOqqa<4Nk6dzUxS*mU@=ZCE1&mFZta_p#ghf`QP z_Znm^XCCx8Ng(CMWRz74tVo?VnspA4}(+xVGY5hXg=bSGm&L?UuM79C)> zKl#w6zs_ZA;CF^)l&@-A0%PbOkwisJNiW>a@NUGv65UG;-tEh(xvW89a+&MYk+}Ta zzpS`sy_pOr-T^7U{OGJG@c4R)rJQoTPo=Ow(ey{@ignbZ%o50Fa~@z9FAH;90QB6q zcXlp$g@nUcn~bRLycnN`6QJGxFeSdqEQvfGl*rv2SVxwBk5 zhCOTD-pAkU%>Q=^mH8y(g>UcP$SjIvt6I!EM?ZJdz81pUV>3y7!VEZ}o%9b}=D!pD zZp}YQNG08=oMVZ6Lu5g&sqyg=7RPm@JK4s3NzZ)qep|fISK=Qi0M*LFY@o|hr+ke1 z%YcT3m`o(OU}}z{;MLhZT#znJ?-Xq>R<=}(ZMoc06ekV(x7$;d^q<}wrSGvhLF^W}ju>`|^(@=FL{>-|U3jArn93kn4 z)_^fBf!_-t>!Qwab!+G;Xr`6<>EbnSPqm$NE}cS^ z>?o)}(j;J$5KE_0iQVF(2glcb);kttS$F2&+?d^bsTn9TP=G$4f;s9{jkeUG6nv46 zqg-Xll*)i9Y>v=rh&dm=w58DVb#(^SoY{<$u~+*Ooc;8bnK0%u`;q#CWaq_6Nk!76 zlnmkQw`UYzP9^Uc{B-cttNN$~q3c!vlYhx0dOlvQrz|1BlDrQdqW-wDN$8Q#K2JN5 zyx6p*NPq~iY-LshP-N-w`A7{Z=T|yKJ~u)%l4d2f-^vP1;o`1QsQ2m+E)mVIe#A@A za&c*<0cJo>{{x}(@7Y7az@4&am@M3L?f_-mBd(ECQ=j0EI%X$aw717Uk2mfNy)Kn8 zueW+m-!0mBsqPw*!ll+FVCT$P^FPR(J^ghMmT*_elR3$*x7EUbP~|%q(rw+{pHHEy z)Vww)bv+$h+ExKEYc!sSS7&>JHu6|=I@B?_utm8yO2x~6@_?q-BN``scHlhGGsl#{ z0w{F1N7Et6o4&FM3%KSAyFW&ipVFh(JulBf@OP-zD%Z#KZFl+SS0+F!mGB)NZqwIo zoQcRn)5?WZH@OZ;9`!E`klL-c`Jyo!P8TZ?jeP9I@paUV_f^dt9TV(PE3-wGvaQY+ z(lO^9pcRnnvG@JwMp7I*Cpy`rCal>~O?Xb{Q-P9bZO}|5d1YtiSow}uT>09>*Npfo zFQprD&i9ps^ZZUB%pBi9M@mSmtc^mMT^A?Nxo}L?`k#j}2L&MG-X zu2uHOgAh6=n>!xmQO>Ig*>%ub8C`Yjs(jVxVg1R@fa`qM*1Cl>=-Sef*JC~@=KY0v zowI(oLju+PrAr#LQHqPNTo#y6aEQE5(S+m#{}3+gENW;%At(sB};CBq0e) zQX8YtX@$oZX`^0~_E#n1R-@1bbQr30XYx>J7orGDa_sCJB|FN*~rv&>eg44U$wG9h9!&jbOq#J4?EWK%uJ?13EiERa{CTl&)G)8n~m`Yf)mWY6)Y~ z;U!Y(7bL%hFP&E8YXlS#;*MkBWVYV(|W0_?&|z4!r49jQzh{;J?9m?*Jk& zaP$0J9#J-8Psf+WKQzqRAF36~;aCSz_5o%T(0iTk7#&2>y1#LrZQ1sBPNSNTrg7AH z>=5Tfzh*DIE8nVNysfhJ+{U$vJle4>ghu0GA7@vG@bLK|+qWe18n7Sg+2#B3X0z+M zKBR4|c1&J^SBd;1`EaCEu|~J!BlFpbvV1P2;l1)O)C1kQ#7pH^o|cO~42-n7CMD4Q z^8X;SsKncd2fI*r`3MKe6V@K6R%LQxMp{tR!63OY8Ht}v{}+%;0TM5xkTSoE_*u)K zSryiuzBcOaY0ZHSY=|U>wFU9?hW{t}YpdG1TMzNXHERyDl-bqkSIKMvs^ysT@gdjh ztr_crb?}Ego?-7VB!_J2ru#1xG00HT+I2pYY-5~v{#w4^ZGjgdUnP1iluvx+JVpMr z`83Fw02zQ0-^KUODBRk(a$+jQc-FyqSt_I;ksBT(Z3(~1uhf|6%lS$>WclvpLhDv& zfT~DWTyo(LsYUQjeo(Z~M0jJORtbiju5PIp!mA2?L~BlH-Pt}_2-4MLt$hn)5T6z zw&h`TLuH#kF*u?w_0Oa*1zu{$f)f=wna1 z+xVK01;`8a@n{vzD zMWe{(+r+w!W(ua?lLpp*FIx?gj4A<{4Oxz+_XApEuPML)cdeKw{%zPbzc>65&EBXHh;|$!argRJr)V#Rb1Ke3J%CIwgibR=hWHto2cp12 zSQch3)=U0I?fguj3AW`{I`#tx-Hegay3^9(7=S=dW}-{_ei z!PIf2y}orfP1Rsh|B7d~4pny05!CPlZ2QI%(!rGLb78z+O|QIO405ux}ca z`6J@6#SuM~ahE+97E`!HM&}m9oEU~&QfK>-=UbeBK+ls9ecONf!o{2A1_FtN50h|` zVHe1^qVEsMs2};MH8@hQCU(A>*ElI+}6f9LKk6C!=>@D`x#)$yX zi^^S0z`&KZNWN?yW))-1m@4W=K+Os7q4>IuqUAl4#~dn-#nVKuyK}l6u@*ThM`jIc zGF3=!2O0;^Y5gRe_-4X5LJaNUhZdK>3HT*CXq^;!s5a!BToWu$zd>b04w@>on9gvD z0ZST@O_h+@KdqSqwK}E4e@clYF8wyySA1QP@Tz-r9RZ;Cuiq4=iW5gRk-||hg zjOiPNZO2Us76hlp>H%}Qy461-zJ-wMGlVflqjg|llLpz7KC*!{>X=%H2LYVYWYdI; zEf{u)ACB+eg2^a{HV9u8Ze!%Zu97d3f-_}c6B+WP6VulljbRCT4{ zSmvYi?av#?wBBkp;~sZ)y2hP4oy|Jp;Yj@UVm`B)YGLPaLC5KMF8uzi!|eX7%}cxF z2ajjdeo9W;RI#{V>upwlsyxqQrv>ZAdp=r@_am*ehUaYQbjH%Mgu^?R`*&9`xHnzd_XCa9AdwWlr>A;I(o*`B-KHtQAHa+aQQcXVhQ>J zJENqzl1_YWoyQ72C+?0lN*b1EkvlD>t5uqD=ThWIg$7om4qx!Q_@=g1#(h<$DTG9ZqXk<;|cGxN2v2g;(KKZ z#@_j@g~nP(;DVMltGRYIF*+vKxpbYGYPh#{Z9Zqq{Tn$?V|r9#vk*}`fG!>Ljf>fA zl+buaq`JjdKy>s*2Qs{ zPL9iT71-G9N-WWa3^&#)5YDL57{&LfAOIbK%X2-LHA%1Fc~qnjpc_#`Hs`L~UdBz< zzUdZM0?Lr6wi!jxxJuxP#TOCB)$2n`1w$BI-en9L{BtC|$5V8CFx0u<$QpF`gbew6 z%QpxQ9>SMYU!wY~)JX?($w=MS0>)5vymDn*CThbHF0+`>F9-`#JFgj*cfvt_kx$MH zhQ;Fs?H4o)`0a!u;$}`{3?vL4uGA2(of#x~?5$S)+7`V)roYCT5RX6<;T@U(U;zx@ z*UWFRw#F6|5s$rx?O|iqMTdXefdSNXKx6xxKVmsP#Gsk2A5`t{So>6}dDmR1_BEav zCe|U-m4epk@EAgeImdDf1xPk{&PS|&;B`ASVPCGZQW>04vNTys6eq(XPanQ+x?GGS zRO`C6&2VvWwNErnK+YB!8;7Sjft_C*k}zMcatfo9h0=FVE?IMcFYH*09cwnXF~o#s zLy7tg8_Rpmcj@$o9n)!bSPTIrBNQ+Q_$OcyG#&bh1{2Gmmq~09bBfFu5iy;=crds5 zd)l~2Z2}Xx$by_z(TUH*;OBa;r5gfa+`lRtP$kPKh&fpT66a`otI6$%Rh(?eU_EH3 z^FTtvCV8k;)eyK>h@ij_leki4a>(n}8+tnx$K1v2wE7KBl_wf9qgs~yjxD>R?*=nS zY3?38o0YgE>2lt2>J>QtUPW3f0ws-oOSnF!9Ugm~!cMQwH2kF|;~v|}ane>sDAQMz zN2s#Zb_ekH`*wk!1qGnczx0i;VNV%b4g;l#iD=>zVY37VztgiDnIfU0$yh01k!?dz z>sq;sj!$5o-epY0<}qV%nox=Q*99)bmNEuVMp@62&1|lQTt&zbrfbCCe4!wUEljnF z;OvP-oNdmmxc|{c?#AdfpqxKRV|W?Kb37Pm=?0HAF}=FuoqsRx?(?CLZG($(YsS=2 zC>nM(QE-$(aKnitb2Ji)3K0M)YOhL`<7df*&TO{wv!8{iRa5GiFBQ&|Rze&?(`$&? z^w4?ifkDLOwD+}u5(auM^p}$Y{@0X*sOOw~Qk zBw}NetZC&N78H$j@#}{3Wq5DuFzZj5bBsLV4z4rTYpqF~$3O5}FOGz(r zh~BL?c^Tx5(KZ|$&GPNdxOho?1x+#V6UROh0S6mSA4N<95iMKi=MvK?8^z`!^7U`U zIHZ!TTj%#jahpGCHQWAXmXs7RyPkWgyi}S-ZEBzab%$$>snwhGnH>*+#E;K#MG1(w zVFa3H4HejDlVUkzQpcFXD4V~MWjcVNx{E(pkAn|sf5-GJjijP9UmkC@cCsDAr-`(v;&gc`Cda@1{M z33_T9SmhA7WJwPMYGu4T>AI9jzJO70wGRvG#(G|W_r_}?fYS?iQOSboNrRzK3F-Cp zjxMxpm@-r=hipS6XqnxTra+}k2V)r%)5s|7%$(*1Zxl@RskPRgs{fUY*?LgR!}Vz3 zRlDgo#sNIeWSkkpH*3@W@qnW+WB#t~$gIv#=sxeGWzR3B1DZ4^5I@MJjfOA79wRe) z;;7R`bH$~8?%nC-<%R+E`V-S+l(b;X^3@m|VP2}C9jY{DWofc|`%&Kmv(|er0W%Id zxdVE?GP0r;j06%;fIZUXsjQ~oRgnXQ6$+$wU`~qYu2H;Sq6Yay^kqhWvrk@VkIt5V z-PVZCp3}n}QDvo?_6cWd*E!Wm?g+bH@#?YobEPYE(TWkyyJ}Ox7&*DUHjBYjDr5cY6*^c*Q+V=V^G0#(XT9|UwRfx2UPtZ4blE0U@ZHJqqVnc; z2%7iN{(QhfCD-(A1_aA{DQnm33|@7ocj?2zi`T{<<^mD;Lie|0rK(H9D4+9*zlaH# zT=m#FDsSIBxm?%qiCH!In=(IYjJ|iYKTpq=ak5HTB^|R_O&sI%&-{T*n49M~A@n7GoyOJCE~HdB(`OyOymxin{Ep7|Sba43 z`lZm8zBDip$>O)1K+;A8O52wi&kM>xq%R6ZV)6*zP~;Fm3PSuKq7Jc;PoTo{^P4QL zIzs61>o@*d#>tD!2NEt%Qy15R^Hc5{w(+&=Pt6Y41qHxSa^~UHP#tO+{~3DR&L4dK z%A&J&_Un|eIPUzs=EjADPrdk1zApp|*=XczPW_vb#z1|YP{$u~CpWwtUb{3hn;rg4 z5u3udJ@ngvYGe}}En?h(wlH{-&%W;)tm5O6JKTa$wIPpG9z+K|uJYme2>M~A@B_lq zFl>_;G2gkWw}uy)r(OFY#5+mx9$|SPX#{D`^+A_nryX#G_-`-)#7(`CT%pIjpCVjB zpCGLwF`_UxGY7-Y92s7Bac63qb=ir$4zSh`6U5f?8Uua=`zN-?B53ZU&4+466%1Tuz-}q#0Im+9&&s0AvQ>hAK ze$-yxQAKoL&&!n>C_jQ#xXb7I_O#Lb{N@q2&b~GjlZ-;B2oJ!_%K`Zij7OD31|;U? zfnBh-=bT5J6e(AGBP4=k494A zq5bisIr^YlRJBH{@A)N@{Yy2-_V;T~R+H`~!HE|ypkdt_gB+*_kI)w4pSvgcK^!rH zx1yp~XB#i6%v%V-x7>bHI^>M`LyS_op4gNnRfcMh7on(liZxO4Ay)%B>RTDYysG_- zUfxuQZRGd^<8byf(!ckN>Tdf|oleM1ZUMpB9X@^ZVAa+LHni^^SJ^ivmcfSerCBpE za<`M^d8u0HH}JN@RBBZ2vjHg&y_JEU0Pe$D)t&BqN{kx4E+=lqphIqDEtAawfBk~X z`7}?CT9;Oo9U7mD85ysD&jBghYzBX6Bs1|}zzhyHqGUGuV4lk*Cz*;I|8>U_!{b)s zrTb+!rxWb(OGbSR9xs;Q@wMNnLO&|aZ&&VpWc_ww|%54t=7m* zc%KkT{Rn#*m#iDFl&cS}ca*~q0yJfb03(Yi@<>iuGbNFyn$d4jgWsH^5AQr|k66h5 zBzip6ED*oAH;5x;&D<-I9R-SNoj^B8z$c9gUe86;s2kR&pS~Y{A9+``&rXl`XSH0= z-_9?JFYy{*3QI)+z~#`qqKu_@2d}c*@{9sfxDV4nY8*!hyz7)2rbS!3K9FFWv){&z z8L`FhiJq-_^cvOoYSE=Z&I_ZQiP2oER%ImFsrTwJPHL)gYHOCHtqn-H(q7W9;LZ## z-^>)*t3FWF*KUPSD3==^VabKK4pTllL7P)!$b21J@_?E zvB{L-10#G)-c7(?O%sX^s0fMSU&9UEUl0cGF~f}cHrx{(eeA?BcyVr_`=y@U-6;kq zmgx`maMeRL-uMQz`?qF$wjZ~XFEgwAy2Uj~?eW%4p%$_e%fj_FZ%L%yo;hSrbt0#} zd+x)PM65ufQ5q$qi?}=Lr_u=}I?>qZ0V63+TPUJaILLN(gy{}kO(!KH)9YmKd5aXB zQ0rULv&pz~f6dfH9W8Tx5iPpaVQ%!r3ID6yCEi6TDL7 zTR2!mEUlzB>E&UcZ3jSokX`D3+T6?Bd^YC^4)OkMuk7E9jKS=NbDx=VQWlCGflVf? zw?L+;#x?WTVuvB}ul1!mV0G zDg$f+-#TqhMxdG~MAfUyXLzJSDW})hWhdB}4ZnKLA;#7Z5}ev3`lTigtX=dsf;V0X zx?sr{Mw2DjOcWpTyrJrg?%%FMTe-~)Ow2*#yC3eal)$rJu`}7ynPc-S$P8w~Vz4+Y zUl6zB)EImTi>1SQ|85&jw@ngca?pJ|?x7q~li>}Nz3oUPgbx_T81zjFNRaF4Y#Khk zdr{HUG%*-nLPvt0utnhbqVFILiY(6Lz2ObJMZ0$U(}XJ09B|6-*P6m^LYD5XpuOCG zi9N7X;CjObcxH7EXAfNtEHJBa-H?d*x_$Wyi8r+ULqS@~1E{+dlcm%wv=?k*v~@Qx zIAv}~u@jG6$kmTl_Z?ml-(Wm@07~tVt!i-dNs)`Sbn{R1T&Fiojucei5@P~`gAzyY zp;h;p8en>R>o_g7^AvsA(Z_*VBuYC7V{NExDviSqQtZPzA<;2Aj7yD!6E%zNp>MiIqD3!UQg8(?`G?GAh&|j35leZZghQVxs)0=#n%q>5p zA}yLxd|_a8BqbCatiKcsSaN;p+?yX?<_T2!bni#&%MBpIWrS4RN4P7|KJ=l&8!UN~ zMr^4#N1|M+bHEF}$By`HSfY35W8djt=_v(sPZK4y7!yp);>9EqgB8wr{MU!^z|{;m|-{ZI_RAH^d~YSKOVrJ?-CB+!;aSRrum5@orb0~20JEk zux$SlBVsBJ;HzfmDxD`U{%Z1{VY-!KarYvV=@^Z7T^e-S8k&3$7YQt+UB%ecM6&(! z&;<*$X=)Z;RLau)sEl?UAbsMT&V)g-MkVP`2@#{XO;-Ff18$gosX~!U#9hrKDcy{M zVp_-}{l}L0msKl%D+war6((HN6c@o1IOMB^CPanJ8@3aXU4>KW3~3S+T?e1(?2&A63vb))T)@uUJSnWs-ih7x552tg*52FlyJ9P!W)8 z1cp8(W5o1_P$Gys19H$QG0Z7P#H7T22?#JT6}hL6{59latpnihzGMj%)Or@h-gO}# z>^zAWKj=-5|4`5nT-j9FlufZ=h_IXw2{WKu0!o+eXaI0WM#N`oo$7>-wMZ6O7>Id< zGl$}1ll6m?ThB+bUGop!9pX7YNC_xO1!3q6oy-P5oYwx^iI}R(2mvF987FsqpB%(o zUznJS@aZC!7oMduLz#l?CTT}MUJIx^RK|Auzo*|CGmpgtxs55KDv!P)_E^Ny9Tf`j z-~M^EydJ9-$ubG;RC)6`QQ&kCAuvvPj+U z45ckvTuS>!0MR!Ol|1&<20s?jLWD=yeq0$rjrL|d_i$^;8#--HRrT?-#?A6I!~Tga z(JtNiq4l5l&}U(1b2d7%{UMb<^YnjfVN^-qo%$T^R42yhSo0mfeEj~b9Ya9KE8Gfv zElC%N$rShHWH-*K4r~TGD1}-YFsjt6B$Rc0fH+w_c|e>G^apsfyQTM^2LJkc|sr9IzYbVm6nJAH4C z$fDPQ=vWV*4?lr>x39_1P>VDB5(Pw8I#lzKS`2gnp4s?!3SqMMM1(8zVK=I3z*$!# zeBgs-V2Lhw%I|mWm^_;ie3Cf2mGXw4D!J6zy`o^Oq*KaL^ z%*d3Kl%Zi^arLn~QBy4rBL<%oOJqdjdSxydlExjUMW``ew$%Hdc1<3LsK*SmV?Q}Q zoHIavC#=)uGpf=Gi!4{I6ZS}E&#H9I{(#r@z*3k|AeA)!zTf^KGt~^w0m%UgGlhe& zG2E&keJ`y;{TD&0bjr|Y3ZjCd*&W~czOuei(`z^zH`y(=Rg*elJ`65Jk^BX9S6LCPdGX zXg+csVm|oM_G`-w)rn2#F*f1vTt5k|wI)Z-p~z<{6;jBheyDcRqa3;rh?%1trnR~B zXjS8l!(oq-33)_eF)Wsmy3aGKRtgN_`x<%91}$c7+;a2z&HVEY{`DTR&3`UgEQ_J< zt7PyZ<-6yu*61+%%kQ1FpWi4eKSem|3#diBNX!)1Q`uJ>~ob^c@U zoj+Ew&~$Hg7ntb?W7O8dFBd!DevmI*`w88EyM)76t1#lybz2`DaD28(?D*_t^!iwk znL&4-(t+MvV2^M2^Z)Fx1!7|{gS+Yc_SuX6@%I;@j`G&p=P73Iwi!n`G^6gB+|UsS z>#|^7?+ocbnxlz+4XYsxn=Qnq1Yu|Ucc%IO&-Er9x8ks`_4=+F>>{S5MmC?Y$8F>hk2|06 zX8l6n;pV`AZ}SaYszXOexs}^c(ecIm&!Pn{+aK9qufPNm==JcAZ$A8voV+@XB>=iB zSyOv^`;S_CpMIVjd)Y)51kF@46Ve*d{^H*+=<|FNkP{6Js|#6y(B zn2IU%?B% zvOC<-@9ah+KfloHT69P26*b#wT7b5MUHetH0D@*L#q@`l$J9Tgjx@be?`VbUMz#H< zld<67D%(D`2?QQ}EsB7ssuDS>S2tMy=86utw(ex-I6u6brDW%_z+b?`Z?1W;R~Rg@ z|2b>)6S^rJi-oMZ*$Gdc%VO`mG^A_NPa7Ku3>LhZlV*+x>(Zhwo0*g2+k|OXwY5a9ld^Xi+Y^el80T(kfKUHDRoJgw- zV^K-&G#XE#Tf~bs=Y`Aq6+2gELhnz4J16uiNenXZDMMxhkTQgRX zZ}V26vE34vcC&qIwKT^pW`0|vol|C3`8gt!PZ5I$ca0le^oLoi4r3D+oj*<{GXCOm z#Gdg_UYA8MHX1K@zwDi%)Q5ik$7bG%xmCeJCI?imv{Z9u(P6U%j9Y!lW;3G15+DveL{r3-v2C|Rh8T3HZhFy zH;4dZma>-={;UUb{lVsk?NT;=%O6c8(~j9G8;)Z;0}SvOpSZnJJJ!gWX(P}^0H7H3 zP-LC^Xk7gc57x!Te|Ze>q<)vm9CJU=cvQ9ceR*Wo4pK*=ilXOsf^bWO8(cEKx#GW> z`7>)wP#kj}REBzNV03HcR9P5g7}bcu?oB3g>y545+8Gh7ENxf4hE`A_V(7NnbS3iv zjluJWT*AYxd$xdlc{9`ISwM1LptVX9^9 z#cU%Nb`7UvDsNIP@?;hA>jr*cHVn^ zi06(1Gvvi~m33y{agcsL(C^c$QlV}7h5i8v*~erSJC{tm$oY?n#`>o?>Qq@6Mn?;*~`Cl$ius)d}29A^)seE*gZ?% z1RIuS={}__(!BZ@GO|8sRussOu5*+5r9*>NjZ6w*)2304_`ja0a7)GV!B3+!L|0F` zed8}`I-6zK3hJofh1GABTjWKoJZeQaXUm1)rWpEq3uGr!>RgXA5w{M0M;7xHEa~I< zVBKE?W%CswzkF@~B#9_h(Wz=Zu(m%>U+T%@k2Wim#pKK% zg%f8MlvRrv7-?PGP=`*uDKj4VJP*OSKXMQv9iKIfF_o$oKJ}nd_ZHs9K9?!R)=j#1 zcB{m#dz_$+YqyPl;W7RGP=WC9bW^vO2l>yJIMyF50lIYfznVJlaJJhnj@z>+jZ(8{ zi5c3eP%~<@MeWgw*_PT7MW`*+8dWv>2o)YhQT3?3ca6p#C03Lu6(h0No9D%Qz4;@5 z>D)9z$rB47#&9SW-}2R=syu!?bloi@Det`f2BtjeF95 zMo)d0nU`(o7T)G_Yn}aMYuU#~4(&FV$sv z50P(%a;=^|Vw(E?hUN1l$fkHN@pv&3oZ^zqo=Yv!)SF`Wa4cZ;k5z$jt?5OX!tlV+ znOQqai{fti%+p?F9NI=^QUxBj?W$eQ^~&K$V2%+A&*ertQxwJ8jLlEL8n42_1URTxMvFK7r`NBZrSA=#3{fh0kZfBJ z-XLvdIIP;H9!mw4a_y%Wji6uHD4I3+ukgHvLSP2$?g|RV+@r^_0;H0L@M?2ut0X*N zsob>{n@wBPc$DI*e5z4x!CBx+YNPu(;E-o-iVG>U%)c(XTH%xn!)t*&W2GWRVGd`^Yo4_!3;&c)nY z(L_ANTx)yS)bbTeqRNt$^l0Rp%dXAMUt{?gT^~Inyf_m}1QU5MESE za+k^fg`6N&8ni9dTm1OMDvP<$hJO^)nA9nEg8FaX-YFx=$bVNn4tHp~8W#MAyI23O zChJO%3U#g#tky%)yNi|zo|y9_Z+>LQXBrm98W!rEIP;Xh!6i{;WD-M|(`PH(rX&LU zkm`LusiDdq6M#|M;DpYhh|}DB579)ee9K%Xt+#H>i@i%qiapp7BC|**gVYTZlt|;gi)X&ePwcU!o zxcT5@Be*WhXQXLliXuZbP$goN`o5DqmR!dxC$#8-omU#}k?CbT_lvnM_+EWUj4(nq zQiL^lp{<*tuQ#Q_WIk7q6)_UiJ*gBt7kM6@CbBCJXYG%9u%8m_0&565Fh~NXT*uVg z-}o@QWXKvM792Cg_0WFoZN_*7(FvuxdGpn_Gt-Vm^13V|dX+k{i%US%Htm9H{B*?l zTg%1go5=LC%OVz@ouAf))~ z{MapkNt4@LmadUPl}o+dt$p>p0WvJ<{4V1X$FU}N&}&Cj{-Omv8fVwCfosDQsAIK3 zRkc-UOGXPY00tRwkl>EX^ztKv4un#xl`zhk8u|1%*HG_i_?v80Cb3TRfm>c~^9>(h zue{4ILYT~Pi4A{>eQRhE03oG`JsTJr$$9OYtXO?bm2CW76_Zwvj@l zZsul%yHfUKl!{TFfu^{R%41ae?7EBMT`9#F$sUKRBD+L*m-y zooC#Ex7U;+gXn$jyV8pdA#)KjK`D+}!;qq%RhMR@_?i8p)aw*{__z7SUx6CbLMP?$ zvLacx_{>BDFjq!B1fQ5aX$%ouButfQV&P1rzvS&d+?Iaae_qqN$1JXmFii~f=-Ip| zjaflh3>WBL{8*7y)F9;oI~SLj%JK1myP`LytPOEhI2GEomFPNW455uE1?WjQCFNgw zb4Q$u{dk&}Tfvc6_<(yh|4+PYDZalkj&5sAP;*eB#}J*ySU(mN)gY}Y>ofm+wz#Q3YEVX}6iIH#^4SyfQ$MQ0pnOFwT{q?H=xV^1Uf}%RZlA#n==7OxR-$ zOp_!T!!qfctuG(4Te0+JrOTpUoikP_K_M)up4rU#Xq?nl-m)p;Owm!C3H?wJ%^IA(r%>}eTdzYXbOvp<$Ix@{pAEk9(x-f}u zuf&Q@-4@#07PORu$)fn8=W|n`vIk?5V0k~PVJ6zoK1*S3k-W~A2Wf^p+8k^XYy9=m zp(YC-z#$$A&w_6<;ytZfmnd|AHr^1!R(svA9a#?*`2hyWay}CrQqx~AS^SVoTQd?o z5-Gu9GZ%s8!<5(g^v8YFu5^mfwLFe2uly4;wXIwrRFtn)t}v6MQ`K-=6;cm&M~<83{rT4UMQAZXy* z(C#(+9|Y#AfW1JUFNJN9&{Wv(vVwI(0OZG)h<7Oh5ywJ5z_9-maFl+7UXb{?JJbo*Kc^M z7QD<tL9d$Ow zuoq)82<7uh?pLF^i-PC$`-(Ee&}H$Wqs;}$!TEC6hW9NKiHV81owdG4p*Y3Q zRB~Iyn5qD8P8)MTm?pbL+I`m6pXug&JjbE{X)&DjODfSNPQzV=&ZAhAXFVBm#~4y59c?df3F(?4Of1I>Gr(V=&R9}+xvWFET={T?WNV(*LQVs zUpvW@L}}3GWVez==YP+LJ81Ev=JE$E=V>4LbuUR5X8_RjIw193?toq3$F*k89hWUmjxYhk7CSSd_n!vlNDV!vQOc(rOwsEb31bD zdjeK*<+NG6J2Wb;4{6j$yP?RmI_Z}ZS(!hrs^TI#QNDUD?h4orC@iM0)yWFY^64`w zo_Yc)9ix)-n3hx4tB)vtTwzD_JAlpYxLPXJs&!w6MU^%1r5t)uDPRbl%Rzyqhb^3u z!NaUa!i}AAwfOZ`LfP(%PQ2`A)3ll$DFf-)(0fJ<@=7~8FR?F3`D1*S*lb%yn03}i zK3&qSg0YxP4kID<>gj$d^YN|<8}k(^Rh)3D1b*c?!++#1e|*!tH^YXTT(X62McK03 z?7twfHAa>N&V+WD(bm@rVB!Moi5ZqC)jGlS(aesiGBMd)w=3Y%t9-2!t5?!>ur=Pf zro~4I;69Ee;a~OoytA865z7B-8K9AgdNOi^l_fF}Jd_G_QH3#wmcPHG3OK2(Eq*Rz zB%&tQUumpSgVqLt78M*+J!X*SYPMBLhAsMQ)De%^ibr{aDK&ujd1j09yx~CWLQ-g| zC&H9LioU*sflM*JfihoF3GlI#cN+2x{$f!bT- zKg5K^H`Dkjs0=@1%O_nos<77DMeM836U56c5)V-1lQ6T0;o1er+Ajcd5RoORY~Oe` zl;T5f^BkZiVXXUNAHPeF^2m2f_iNGa$UyDtVVVLD!_IK~h-?wJJeKJNMsC=uZg*|% z-jn`$H(lPIr@W3O$KQa#haFOK8&bRxF8%=fz&o# zD*sv-boAtIv&~37RQ+Znt88BjDdH`wC}3x&0pLz%UNe_>zaFIIw0pKoin(6+^sf=7 z2bSEuW`)NuV# zv0WGyrv&gRs%J8jt@Qz4xX8Z%{GDTxO`vHoCyIPSg}OyW+JKSIU+?PR1p$MP%9(Skr)8mh^S_oo93Gkpzaw?gZyC`0 zBVEmSVQOxD0AL*O^=Rlvycn0+F+BVUu;)9)@Y~{Rv!P|8>bc^)c+VR{g<^8`) zZfAv@)MKfkBxNot@;<_}J1?jl92a1{DyI$U*N5}brcZ&Y{)MYmmfvqGJ{1YIhb4+< z+^mCQF3DdqF%Y^hXV8aG6&0l$?MW?DSv)Um5eyPImah*q!m?;b#6JQ229SZg&q-OJ z24m=Z`sHoLgSjAeX%WoJBkqw}%&F>y8=-^HlX$8rGT}vuSAHN(_vs8juz4xS4Sct{ zEXoMS5GjQtp^?=$lg>ukL-NOrd&5Vv&5QTP|9M(Saxlr$iz<2eJU@x<_numD9%l=d z8gre`NY{u4#3>RNl4QM*f4uX!%xFvXl@k4Ajt=X z6Mfz92+0W=S7R|BRj7LA-x{p^ohu%7as-G}*&$1yv-n`fvnJn4Z zHnw76?;q14Tg_`H+il|~L_q3H zRVNN_8%TOiLY?{ay1^WH2sWC^i#*xSl6UnFZcA10jYzHSb;QkNJ12Bjg4(JXSxZt{ z|IT%SZKOUm1Tvv@*~RKU0WaWRL1i8M1tV$lXBR)|bTP@xd9~1d^CjLz?yJbHBxEB{W$x%Y0DvU8v<*y)fuSTgG?s|8Z_}6LxgVp@5XsZ4R z7cxn~bR&MHsUC_1rigz3*5-f{W zrWx0Y)FOJ1Ci@#TUB3ke3V7JuYiq&8$$B*Nqb5cHAaOwdwpGkfC6FS)N-Ad25e1^k*>r;xD{RQ^VgBPg`Dmd%l!V2Idl4&F)XHOjQd$+{m*=ELuH5 z3^-v>B5#O)_&mvH|f;dyX$EM5#3~LIE3P!qXE|Og$3i}C z%MpZHnYrz^ENL8OMkE!Wq+kUqzjJtHXO8Md?Ig};mgq_ zrlv7v{MO4082{JSf!*p39yW)SyAX7T;!#|J{p$ZEToP0E`I~|VmTF^zu?j)_^aS5$ z+w^^%R~g}ffK$rA~@b(k=cf1~?B``oWTbo6U>dNT;x z#*YR~1E5b$2gxnY-_~y!Z--nMl4Jq`4AwywmsGV@gqMl6;6ry2KuCe?{cYR$q&Af$ zzD=g^XSQ0)UH5^~6rP&U!p_FjvXp-~$o7v&Ex#;2=n7=Wl+; zv?c3qMI}RUi*x|h(=`gsP+y^6w`omfUnjgwgI#{SE#0}fj@VUMWKF>w01nu!TMoPG zXP2{c@uIGcB5H|tjj5{dX8NS4m4C=Oc z9_#B_7ZG2xqrKx%KTzuj`o{2?DWi}{;HgB;y`hx+B@w2|y_TtJ8Xp_Zf$9Sa5@D3O z7!p1Ut+^&);fkayr^+%~wwJQtlK!jy?VzfXb28nq=N@H19Z~hK;exo?8vYHVwFdtZ z$D373uIPb)=BCl-QVcq0uGk(F<%ASxz662(LOU(wI7x>XtHFf&lRYE=eqI^_!kG7* z;(soPDNvK>YzrEz9btY|g+X@xh!#7bxU{5s8>3bc#%j>v|CK4b`YzE=X#fb6Dh%ay#2Nw-6VGeo1Uo9;=($@WYn@0n|8zlSVV~Q zet@5%5`*~nCw00ogL%~~@VT<7X~GPe-4qn`EsM|AT8$0SXO`sIdjM`XxJM0OZXgBv zCB^gCOwT#wj0|YgF9iH+PA>dwPM-DeaHjTZ{@2Dl?PvY|Z@WZ|KC;VL|F6q<_R|fg dx^DnG4$+!bdiSvIxR-+bxTj@s_Y1@>{692N30VLD literal 0 HcmV?d00001 diff --git a/samples/speedystore/images/cluster_monitoring_hl_architecture-mfjdOm.webp b/samples/speedystore/images/cluster_monitoring_hl_architecture-mfjdOm.webp new file mode 100644 index 0000000000000000000000000000000000000000..1c6004440d5495e2878e00daabc7d27fdee52c9a GIT binary patch literal 32954 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 Date: Tue, 30 Sep 2025 18:39:20 -0400 Subject: [PATCH 02/20] Tweaks --- samples/speedystore/README.md | 56 ++++++++++++------- .../speedystore/speedystore-datasource.yaml | 2 +- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index d9e72144..4578dceb 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -3,44 +3,41 @@ ## Overview This sample demonstrates how to extend SAS Viya Monitoring for Kubernetes to monitor the SingleStore instance embedded within SAS SpeedyStore. This allows administrators to monitor their SingleStore cluster using the same Grafana instance they use to monitor the rest of their SAS Viya deployment. -This sample is derived from the blog post Using [Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) written by Michael Goddard from SAS Education. The blog post was, in turn, based on work Michael did in preparing to cover the topic as part of the [SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) workshop available in [learn.sas.com](https://learn.sas.com/). This sample includes Grafana dashboards developed and made available by SingleStore. +This sample is derived from the blog post [Using Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) written by Michael Goddard from SAS Education. The blog post was, in turn, based on work Michael did in preparing to cover the topic as part of the [SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) workshop available in [learn.sas.com](https://learn.sas.com/). This sample includes Grafana dashboards developed and made available by SingleStore. **Note: There may be other ways to achieve these same objectives, this sample documents one possible approach.** ## Using this Sample Enabling this monitoring will required configuring components in both SingleStore and Grafana. While we will describe how to configure the SingleStore components, you are strongly encouraged to review the official SingleStore documentation for a more comprehensive discussion of how to monitor SingleStore effectively, the options for doing so and additional implementation details. After configuring the SingleStore components, this sample covers defining the datasource within Grafana and deploying the SingleStore-specific Grafana dashboards. -The diagram below. taken from the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/), provides a high-level overview of metric collection and reporting process. As shown, the SingleStore pipeline extracts metrics from the SingleStore cluster and stores them within a metrics database. Grafana pulls metric data directly from this metrics database to populate the dashboards administrators view. +The diagram below, taken from the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/), provides a high-level overview of metric collection and reporting process. As shown, the SingleStore pipeline extracts metrics from the SingleStore cluster and stores them within a metrics database. Grafana pulls metric data directly from this metrics database to populate the dashboards administrators view. ![Overview of SingleStore Monitoring Process ](images/cluster_monitoring_hl_architecture-mfjdOm.webp) ### Overview of Process -* Set-up - * Set the VIYA_NS environent variable * SingleStore - * Configure the SingleStore pipeline - * Configure metrics database - * Configure "monitoring user" + * Configure the SingleStore pipeline and metrics database + * Configure the "monitoring user" * Grafana - * Configure Grafana - * Load SingleStoer Grafana Dashboards + * Configure the Grafana Datasource + * Import the SingleStore Dashboards into Grafana ### Configure the SingleStore pipeline and metrics database -The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. We will use the `sdb-admin start-monitoring-kube` command to configure and start the monitoring. It has a number of flags to control its operations. See the SingleStore documentation for more information: [start-monitoring-kube](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/). +The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. We will use the `sdb-admin start-monitoring-kube` command to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. -To configure and start the monitoring, including the metrics database, we will submit the following command: +To configure and start the monitoring, including the metrics database, we will (eventually) submit the following command: `sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace {VIYA_NS} --user root --password {ROOT_PWD} --exporter-host {CLUSTER_MASTER_IP}` -But before submitting the command, we will review the parameters being passed to the command. +But, before submitting the command, we will review the various parameters being passed to the command and how to determine their proper values. #### Set the VIYA_NS environent variable -Since you will need to refer repeatedly to the namespace in which SAS Viya (and SingleStore) is deployed, it is helpful to define an environment variable, `VIYA_NS`,to identify the namespace and reference it in subsequent commands. +Since you will need to refer repeatedly to the namespace in which SAS Viya (and SingleStore) is deployed, it is helpful to define an environment variable, `VIYA_NS`, to identify the namespace and reference it in subsequent commands. -You can use the following command to do this: +In the following command, we set the `VIYA_NS` environment variable to ***myviya*** the namespace containing our SAS Viya deployment: `export VIYA_NS=myviya` @@ -49,22 +46,26 @@ The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: `show global variables like 'cluster_name%';` +If the cluster name is different than the default, be sure to use the correct value in subsequent commands. + #### The `user` and `password` parameters -A core part of the monitoring is the exporter process which collects the metric data from the cluster. The exporter process is typically run as the SingleStore 'root' user due to the permissions required. In addition, we will need the password for the SingleStore 'root' user. Note: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user is out-of-scope for this sample and we will use the 'root' user. +A core part of the monitoring is the exporter process which collects the metric data from the cluster. The exporter process is typically run as the SingleStore 'root' user due to the permissions required. In addition, we will need the password for the SingleStore 'root' user. + +NOTE: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user is out-of-scope for this sample and we will use the 'root' user. You can use the following command to get the password for the 'root' user: `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter -As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You need to provide the fully-qualified host name or IP address for the exporter host. The name needs to be resolvable by the host running the `sdb-admin` command. Since the fully-qualified host name may not be resolvable, we will use the IP address for the `exporter-host` parameter instead. +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You will need to provide the fully-qualified host name or IP address for the exporter host. And the name needs to be resolvable by the host running the `sdb-admin` command. Since the fully-qualified host name may not be resolvable, we will use the IP address for the `exporter-host` parameter instead. You can obtain the IP address for the Master node by submitting the following command: `CLUSTER_MASTER_IP=$(kubectl -n ${NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` #### Accessing the Kubernetess Cluster -The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file defined in the KUBECONFIG environment variable or the ~/.kube/config file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config. +The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file identified in the `KUBECONFIG` environment variable or the `~/.kube/config` file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config. #### Run the `sb-admin start-monitoring-kube` command After setting all of the required parameters, submit the following command to configure and start the monitoring, including the metrics database: @@ -74,7 +75,7 @@ After setting all of the required parameters, submit the following command to co After running the command, the exporter process, the pipeline and the metrics database are created. To confirm this, you can use the SingleStore Studio. For example, in the screenshot below, you can see the newly created **'metrics'** database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) -### Configure "monitoring user" +### Configure the "monitoring user" Grafana will need to connect to the 'metrics' database and you should create a specific user to be used for that purpose. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so the user can be used to manage the metrics database, pipelines and the exporter process. For example, you might grant the following permissions: @@ -91,10 +92,20 @@ Alternatively, you might GRANT the "monitoring user" minimal permissions, and cr |**TO DO: Is the user name *S2MonitorUser*?** -### Configure Grafana Datasource +### Configure the Grafana Datasource Grafana datasources provide connection information allowing Grafana to access metric information in response to user queries and to populate dashboards. -The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the 'metrics' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update the ***url*** field in the file as well. +The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the 'metrics' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You will also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. + +For example, if SAS Viya is deployed into the ***myviya*** namespace, you would revise the ***url*** value from: + +`url: svc-sas-singlestore-cluster-ddl.VIYA_NS.svc.cluster.local:3306` + +to: + +`url: svc-sas-singlestore-cluster-ddl.myviya.svc.cluster.local:3306` + + If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update that portion of the ***url*** field in the file as well. Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. @@ -108,7 +119,9 @@ You can use the following command to apply the necessary label: `kubectl -n $VIYA_NS label secret grafana-metrics-connection "grafana_datasource=1"` -### Import SingleStore Dashboards +|**TO DO**: Is the service-name always _name_of_singlestore_cluster_ + "-dll" + +### Import the SingleStore Dashboards into Grafana To import the SingleStore dashboards into Grafana, you can use the `deploy_dashboards.sh` script found in the `monitoring/bin` sub-directory of this repository. You can use the following command to import all of the SingleStore dashboards: @@ -136,6 +149,7 @@ To validate the configuration, sign into Grafana and review each of the SingleSt * [Resource Pool Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#resource-pool-monitoring) ## Acknowledgements +Thank you to Michael Goddard (SAS Education) for all of his work sorting this out and allowing us to share it here. ## References [SingleStore Documentation: Configure Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/) diff --git a/samples/speedystore/speedystore-datasource.yaml b/samples/speedystore/speedystore-datasource.yaml index 9d73231b..7e15c3a6 100644 --- a/samples/speedystore/speedystore-datasource.yaml +++ b/samples/speedystore/speedystore-datasource.yaml @@ -3,7 +3,7 @@ apiVersion: 1 datasources: - name: monitoring type: mysql - url: svc-sas-singlestore-cluster-ddl.viya.svc.cluster.local:3306 + url: svc-sas-singlestore-cluster-ddl.VIYA_NS.svc.cluster.local:3306 database: metrics user: S2MonitorUser secureJsonData: From a7e4355ba56fbcabed1e126fcab3e224864b359c Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:37:43 -0400 Subject: [PATCH 03/20] tweaks(2) --- samples/speedystore/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 4578dceb..ca77b62e 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -29,7 +29,7 @@ The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore To configure and start the monitoring, including the metrics database, we will (eventually) submit the following command: -`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace {VIYA_NS} --user root --password {ROOT_PWD} --exporter-host {CLUSTER_MASTER_IP}` +`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` But, before submitting the command, we will review the various parameters being passed to the command and how to determine their proper values. @@ -62,7 +62,7 @@ As shown in the diagram above, the export process runs on the Master Aggregator. You can obtain the IP address for the Master node by submitting the following command: -`CLUSTER_MASTER_IP=$(kubectl -n ${NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` +`CLUSTER_MASTER_IP=$(kubectl -n ${VIYA_NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` #### Accessing the Kubernetess Cluster The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file identified in the `KUBECONFIG` environment variable or the `~/.kube/config` file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config. @@ -70,7 +70,7 @@ The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya #### Run the `sb-admin start-monitoring-kube` command After setting all of the required parameters, submit the following command to configure and start the monitoring, including the metrics database: -`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace {VIYA_NS} --user root --password {ROOT_PWD} --exporter-host {CLUSTER_MASTER_IP}` +`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` After running the command, the exporter process, the pipeline and the metrics database are created. To confirm this, you can use the SingleStore Studio. For example, in the screenshot below, you can see the newly created **'metrics'** database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) From 34bf272c15fe606dc7051307d8d5a175397ab135 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Wed, 1 Oct 2025 14:08:16 -0400 Subject: [PATCH 04/20] Add user create --- samples/speedystore/README.md | 65 ++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index ca77b62e..434dcc0d 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -15,18 +15,17 @@ The diagram below, taken from the [SingleStore documentation](https://docs.singl ![Overview of SingleStore Monitoring Process ](images/cluster_monitoring_hl_architecture-mfjdOm.webp) ### Overview of Process -* SingleStore - * Configure the SingleStore pipeline and metrics database - * Configure the "monitoring user" -* Grafana - * Configure the Grafana Datasource - * Import the SingleStore Dashboards into Grafana +* Configure SingleStore + * Create the SingleStore pipeline and metrics database + * Create the "S2MonitorUser" +* Configure Grafana + * Create the Datasource + * Import the SingleStore Dashboards -### Configure the SingleStore pipeline and metrics database +### Create the SingleStore pipeline and metrics database The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. We will use the `sdb-admin start-monitoring-kube` command to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. - To configure and start the monitoring, including the metrics database, we will (eventually) submit the following command: `sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` @@ -49,11 +48,11 @@ The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: If the cluster name is different than the default, be sure to use the correct value in subsequent commands. #### The `user` and `password` parameters -A core part of the monitoring is the exporter process which collects the metric data from the cluster. The exporter process is typically run as the SingleStore 'root' user due to the permissions required. In addition, we will need the password for the SingleStore 'root' user. +A core part of the monitoring is the exporter process which collects the metric data from the cluster. The exporter process is typically run as the SingleStore 'root' user due to the permissions required. NOTE: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user is out-of-scope for this sample and we will use the 'root' user. -You can use the following command to get the password for the 'root' user: +In addition, we will need the password for the SingleStore 'root' user. You can use the following command to get the password for the 'root' user: `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` @@ -64,29 +63,52 @@ You can obtain the IP address for the Master node by submitting the following co `CLUSTER_MASTER_IP=$(kubectl -n ${VIYA_NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` +#### Disabling interactive mode +By default, the `sdb-admin start-monitoring-kube` command will display some information and ask the user if they would like to continue. To skip this prompt and have the configuration continue automatically, we will incle the `--yes` parameter. + #### Accessing the Kubernetess Cluster -The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file identified in the `KUBECONFIG` environment variable or the `~/.kube/config` file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config. +The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file identified in the `KUBECONFIG` environment variable or the `~/.kube/config` file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config file. #### Run the `sb-admin start-monitoring-kube` command After setting all of the required parameters, submit the following command to configure and start the monitoring, including the metrics database: -`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` +`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP --yes` + +After running the command, you should see output similar to the following: + +``` +✓ Successfully discovered resources +Toolbox will perform the following actions: + · create a database metrics with tables and procedures for monitoring + · set retention period to 7 days for 192.168.0.164:9104 + · set purge frequency to 60 minutes for 192.168.0.164:9104 + · set purge log retention period to 365 days + +Would you like to continue? [Y/n]: +Automatically selected yes, non-interactive mode enabled + +Operation completed successfully +``` -After running the command, the exporter process, the pipeline and the metrics database are created. To confirm this, you can use the SingleStore Studio. For example, in the screenshot below, you can see the newly created **'metrics'** database: +Once completed, the exporter process, the pipeline and the metrics database have been created. To confirm this, you can use the SingleStore Studio. For example, in the screenshot below, you can see the newly created **'metrics'** database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) -### Configure the "monitoring user" -Grafana will need to connect to the 'metrics' database and you should create a specific user to be used for that purpose. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so the user can be used to manage the metrics database, pipelines and the exporter process. +### Create the "S2MonitorUser" +You need to create a specific user that Grafana can use to connect to the 'metrics' database. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. -For example, you might grant the following permissions: +After logging into SingleStore with the admin user, you can submit `CREATE USER` and `GRANT` commands to create the user and grant the user the desired permissions. -`GRANT CLUSTER, SHOW METADATA, SELECT, PROCESS ON *.* to '{S2MonitorUser}'@'%';` +For example, the following command creates a user called `S2MonitorUser` and assigns it a password: -`GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to '{S2MonitorUser}'@'%';` +`CREATE USER S2MonitorUser IDENTIFIED BY 'password123' REQUIRE NONE;` -Alternatively, you might GRANT the "monitoring user" minimal permissions, and create a second user ("monitoring administrator") to manage the metrics database, pipelines and the exporter process. +Then you might grant the following permissions: + +`GRANT CLUSTER, SHOW METADATA, SELECT, PROCESS ON *.* to 'S2MonitorUser'@'%';` -|**TO DO: Where do you submit those commands? SingleStore CLI?** +`GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to 'S2MonitorUser'@'%';` + +Alternatively, you might GRANT the "monitoring user" minimal permissions, and create a second user ("monitoring administrator") to manage the metrics database, pipelines and the exporter process. |**TO DO: Does the first GRANT statement only grant the _minimal_ permissions needed to pull metirics? And the 2nd grants the extended permissions needed to be an administrator?** @@ -105,6 +127,8 @@ to: `url: svc-sas-singlestore-cluster-ddl.myviya.svc.cluster.local:3306` +|**TO DO**: Is the service-name always _name_of_singlestore_cluster_ + "-dll" + If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update that portion of the ***url*** field in the file as well. Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. @@ -119,7 +143,6 @@ You can use the following command to apply the necessary label: `kubectl -n $VIYA_NS label secret grafana-metrics-connection "grafana_datasource=1"` -|**TO DO**: Is the service-name always _name_of_singlestore_cluster_ + "-dll" ### Import the SingleStore Dashboards into Grafana To import the SingleStore dashboards into Grafana, you can use the `deploy_dashboards.sh` script found in the `monitoring/bin` sub-directory of this repository. From a0f4c3a8abd57656395d6217b661a31b04aad108 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:14:54 -0400 Subject: [PATCH 05/20] Added tags to dashboards --- samples/speedystore/dashboards/clusterview.json | 2 +- samples/speedystore/dashboards/detailedclusterviewbynode.json | 2 +- samples/speedystore/dashboards/diskusage.json | 2 +- .../speedystore/dashboards/historicalworkloadmonitoring.json | 2 +- samples/speedystore/dashboards/memoryusage.json | 4 +--- samples/speedystore/dashboards/pipelineperformance.json | 2 +- samples/speedystore/dashboards/pipelinesummary.json | 2 +- samples/speedystore/dashboards/queryhistory.json | 2 +- samples/speedystore/dashboards/resourcepoolmonitoring.json | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) diff --git a/samples/speedystore/dashboards/clusterview.json b/samples/speedystore/dashboards/clusterview.json index a7f13d68..8fbf5d03 100644 --- a/samples/speedystore/dashboards/clusterview.json +++ b/samples/speedystore/dashboards/clusterview.json @@ -2296,7 +2296,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/detailedclusterviewbynode.json b/samples/speedystore/dashboards/detailedclusterviewbynode.json index 6e0ddf05..9b3b1064 100644 --- a/samples/speedystore/dashboards/detailedclusterviewbynode.json +++ b/samples/speedystore/dashboards/detailedclusterviewbynode.json @@ -2310,7 +2310,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/diskusage.json b/samples/speedystore/dashboards/diskusage.json index 84f076ee..d657abbf 100644 --- a/samples/speedystore/dashboards/diskusage.json +++ b/samples/speedystore/dashboards/diskusage.json @@ -1115,7 +1115,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/historicalworkloadmonitoring.json b/samples/speedystore/dashboards/historicalworkloadmonitoring.json index bad3c679..bfbf7ae7 100644 --- a/samples/speedystore/dashboards/historicalworkloadmonitoring.json +++ b/samples/speedystore/dashboards/historicalworkloadmonitoring.json @@ -1397,7 +1397,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/memoryusage.json b/samples/speedystore/dashboards/memoryusage.json index d8baff25..f577ca05 100644 --- a/samples/speedystore/dashboards/memoryusage.json +++ b/samples/speedystore/dashboards/memoryusage.json @@ -737,9 +737,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [ - "support" - ], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/pipelineperformance.json b/samples/speedystore/dashboards/pipelineperformance.json index 5d0b2fc1..eeb7d0a7 100644 --- a/samples/speedystore/dashboards/pipelineperformance.json +++ b/samples/speedystore/dashboards/pipelineperformance.json @@ -1362,7 +1362,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/pipelinesummary.json b/samples/speedystore/dashboards/pipelinesummary.json index dddc686f..9026651c 100644 --- a/samples/speedystore/dashboards/pipelinesummary.json +++ b/samples/speedystore/dashboards/pipelinesummary.json @@ -505,7 +505,7 @@ "preload": false, "refresh": "15m", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/queryhistory.json b/samples/speedystore/dashboards/queryhistory.json index 0420b23e..46a6c13c 100644 --- a/samples/speedystore/dashboards/queryhistory.json +++ b/samples/speedystore/dashboards/queryhistory.json @@ -359,7 +359,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { diff --git a/samples/speedystore/dashboards/resourcepoolmonitoring.json b/samples/speedystore/dashboards/resourcepoolmonitoring.json index dafe6869..f93e0c9b 100644 --- a/samples/speedystore/dashboards/resourcepoolmonitoring.json +++ b/samples/speedystore/dashboards/resourcepoolmonitoring.json @@ -564,7 +564,7 @@ "preload": false, "refresh": "", "schemaVersion": 41, - "tags": [], + "tags": ["singlestore","sas-speedystore"], "templating": { "list": [ { From 633e10c2be8ed51927ab40a078061791f339cfbf Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:15:07 -0400 Subject: [PATCH 06/20] tweak README --- samples/speedystore/README.md | 47 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 434dcc0d..77e14ac3 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -3,12 +3,12 @@ ## Overview This sample demonstrates how to extend SAS Viya Monitoring for Kubernetes to monitor the SingleStore instance embedded within SAS SpeedyStore. This allows administrators to monitor their SingleStore cluster using the same Grafana instance they use to monitor the rest of their SAS Viya deployment. -This sample is derived from the blog post [Using Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) written by Michael Goddard from SAS Education. The blog post was, in turn, based on work Michael did in preparing to cover the topic as part of the [SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) workshop available in [learn.sas.com](https://learn.sas.com/). This sample includes Grafana dashboards developed and made available by SingleStore. +This sample is primarily derived from the blog post [Using Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) written by Michael Goddard from SAS Education. The blog post was, in turn, based on work Michael did in preparing to cover the topic as part of the [SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) workshop available in [learn.sas.com](https://learn.sas.com/). This sample includes Grafana dashboards developed and made available by SingleStore. **Note: There may be other ways to achieve these same objectives, this sample documents one possible approach.** ## Using this Sample -Enabling this monitoring will required configuring components in both SingleStore and Grafana. While we will describe how to configure the SingleStore components, you are strongly encouraged to review the official SingleStore documentation for a more comprehensive discussion of how to monitor SingleStore effectively, the options for doing so and additional implementation details. After configuring the SingleStore components, this sample covers defining the datasource within Grafana and deploying the SingleStore-specific Grafana dashboards. +Enabling this monitoring will required configuring components in both SingleStore and Grafana. While this sample describes how to configure the SingleStore components, you are strongly encouraged to review the official SingleStore documentation for a more comprehensive discussion of how to monitor SingleStore effectively, the options for doing so and additional implementation details. After configuring the SingleStore components, this sample covers defining the datasource within Grafana and deploying the SingleStore-specific Grafana dashboards. The diagram below, taken from the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/), provides a high-level overview of metric collection and reporting process. As shown, the SingleStore pipeline extracts metrics from the SingleStore cluster and stores them within a metrics database. Grafana pulls metric data directly from this metrics database to populate the dashboards administrators view. @@ -17,31 +17,33 @@ The diagram below, taken from the [SingleStore documentation](https://docs.singl ### Overview of Process * Configure SingleStore * Create the SingleStore pipeline and metrics database - * Create the "S2MonitorUser" + * Create the "S2MonitorUser" user * Configure Grafana - * Create the Datasource - * Import the SingleStore Dashboards + * Create the datasource + * Import the SingleStore dashboards ### Create the SingleStore pipeline and metrics database -The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. We will use the `sdb-admin start-monitoring-kube` command to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. +The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. -To configure and start the monitoring, including the metrics database, we will (eventually) submit the following command: +To configure and start the monitoring, including the metrics database, the following command will (eventually) be submitted: `sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` -But, before submitting the command, we will review the various parameters being passed to the command and how to determine their proper values. +But, before submitting the command, the various parameters being passed to the command and how to determine their proper values will be reviewed. #### Set the VIYA_NS environent variable Since you will need to refer repeatedly to the namespace in which SAS Viya (and SingleStore) is deployed, it is helpful to define an environment variable, `VIYA_NS`, to identify the namespace and reference it in subsequent commands. -In the following command, we set the `VIYA_NS` environment variable to ***myviya*** the namespace containing our SAS Viya deployment: +In the following command, the `VIYA_NS` environment variable is defined and assigned the value identifying the namespace containing our SAS Viya deployment (i.e. ***myviya*** ): `export VIYA_NS=myviya` #### The `cluster-name` parameter -The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: ***sas-singlestore-cluster***. However, it is possible to change this name, so it is important to confirm the actual cluster name before configuring the monitroing. To get the cluster name, submit the following command via the SingleStore CLI: +The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: ***sas-singlestore-cluster***. However, since it is possible to change this name, it is important to confirm the actual cluster name before configuring the monitoring. + +To get the cluster name, submit the following command via the SingleStore CLI: `show global variables like 'cluster_name%';` @@ -52,19 +54,19 @@ A core part of the monitoring is the exporter process which collects the metric NOTE: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user is out-of-scope for this sample and we will use the 'root' user. -In addition, we will need the password for the SingleStore 'root' user. You can use the following command to get the password for the 'root' user: +You will need the password for the SingleStore 'root' user. You can use the following command to get the password for the 'root' user and store it in the `ROOT_PWD` environment variable: `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You will need to provide the fully-qualified host name or IP address for the exporter host. And the name needs to be resolvable by the host running the `sdb-admin` command. Since the fully-qualified host name may not be resolvable, we will use the IP address for the `exporter-host` parameter instead. -You can obtain the IP address for the Master node by submitting the following command: +You can obtain the IP address for the Master node and stored it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: `CLUSTER_MASTER_IP=$(kubectl -n ${VIYA_NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` #### Disabling interactive mode -By default, the `sdb-admin start-monitoring-kube` command will display some information and ask the user if they would like to continue. To skip this prompt and have the configuration continue automatically, we will incle the `--yes` parameter. +By default, the `sdb-admin start-monitoring-kube` command will display some information and ask the user if they would like to continue. To skip this prompt and have the configuration continue automatically, include the `--yes` parameter. #### Accessing the Kubernetess Cluster The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file identified in the `KUBECONFIG` environment variable or the `~/.kube/config` file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config file. @@ -90,25 +92,25 @@ Automatically selected yes, non-interactive mode enabled Operation completed successfully ``` -Once completed, the exporter process, the pipeline and the metrics database have been created. To confirm this, you can use the SingleStore Studio. For example, in the screenshot below, you can see the newly created **'metrics'** database: +Once completed, the exporter process, the pipeline and the metrics database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created **'metrics'** database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) ### Create the "S2MonitorUser" -You need to create a specific user that Grafana can use to connect to the 'metrics' database. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. +You need to create a specific user that Grafana can use to connect to the ***'metrics'*** database. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. After logging into SingleStore with the admin user, you can submit `CREATE USER` and `GRANT` commands to create the user and grant the user the desired permissions. -For example, the following command creates a user called `S2MonitorUser` and assigns it a password: +For example, the following command creates a user called `S2MonitorUser` and sets its password: `CREATE USER S2MonitorUser IDENTIFIED BY 'password123' REQUIRE NONE;` -Then you might grant the following permissions: +Then you can grant the desired permissions by submitting the following commands: `GRANT CLUSTER, SHOW METADATA, SELECT, PROCESS ON *.* to 'S2MonitorUser'@'%';` `GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to 'S2MonitorUser'@'%';` -Alternatively, you might GRANT the "monitoring user" minimal permissions, and create a second user ("monitoring administrator") to manage the metrics database, pipelines and the exporter process. +Alternatively, you could GRANT the "monitoring user" minimal permissions, and create a second user ("monitoring administrator") to manage the metrics database, pipelines and the exporter process. |**TO DO: Does the first GRANT statement only grant the _minimal_ permissions needed to pull metirics? And the 2nd grants the extended permissions needed to be an administrator?** @@ -117,7 +119,7 @@ Alternatively, you might GRANT the "monitoring user" minimal permissions, and cr ### Configure the Grafana Datasource Grafana datasources provide connection information allowing Grafana to access metric information in response to user queries and to populate dashboards. -The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the 'metrics' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You will also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. +The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the ***'metrics'*** database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You will also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. For example, if SAS Viya is deployed into the ***myviya*** namespace, you would revise the ***url*** value from: @@ -131,7 +133,7 @@ to: If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update that portion of the ***url*** field in the file as well. -Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. +Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. This will ensure all of the files related to this deployment of SAS Viya Monitoring are in one place. Then submit the following command to create the datasource: @@ -151,16 +153,17 @@ You can use the following command to import all of the SingleStore dashboards: `./monitoring/bin/deploy_dashboards.sh samples/speedy/dashboards` -Or, if you can import specific dashboards individually using the same script. For example, following command imports the ***Cluster View*** dashboard into Grafana: +Or, you can import specific dashboards individually using the same script. For example, following command imports the ***Cluster View*** dashboard into Grafana: `./monitoring/bin/deploy_dashboards.sh samples/speedy/dashboards/clusterview.yaml` ### Validate -Once the dashboards have been imported into Grafana, you should be all set to monitor the SingleStore instance embedded in SAS SpeedyStore. +Once the dashboards have been imported into Grafana, you should be ready to monitor the SingleStore instance embedded in SAS SpeedyStore. To validate the configuration, sign into Grafana and review each of the SingleStore dashboards you've imported. All of the imported dashboards have the ***"sas-speedystore"*** and ***"singlestore"*** tags. While the data shown will vary based on user activity, all of the dashboards should be available with no errors or warning icons or messages. ## The Grafana Dashboards +This is a list of the SingleStore dashboards included in this sample. Each dashboard name in the list is a link to more information about the dashboard in the SingleStore documentation including the metrics depicted and the types of questions they address. * [Cluster View](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#cluster-view) * [Detailed Cluster View by Node](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#detailed-cluster-view-by-node) * [Disk Usage](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#disk-usage) From 54209681df99e45b23aa1f38284c5a6896929cb1 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Thu, 2 Oct 2025 14:56:13 -0400 Subject: [PATCH 07/20] Correct path to dashboard files --- samples/speedystore/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 77e14ac3..fc6e45a6 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -151,11 +151,11 @@ To import the SingleStore dashboards into Grafana, you can use the `deploy_dashb You can use the following command to import all of the SingleStore dashboards: -`./monitoring/bin/deploy_dashboards.sh samples/speedy/dashboards` +`./monitoring/bin/deploy_dashboards.sh samples/speedystore/dashboards` Or, you can import specific dashboards individually using the same script. For example, following command imports the ***Cluster View*** dashboard into Grafana: -`./monitoring/bin/deploy_dashboards.sh samples/speedy/dashboards/clusterview.yaml` +`./monitoring/bin/deploy_dashboards.sh samples/speedystore/dashboards/clusterview.yaml` ### Validate Once the dashboards have been imported into Grafana, you should be ready to monitor the SingleStore instance embedded in SAS SpeedyStore. From 4bd7081de60cbe29b5fed03ade9e28f43aa8598b Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Thu, 2 Oct 2025 15:50:12 -0400 Subject: [PATCH 08/20] Prefix dashboard names with "SingleStore:" --- samples/speedystore/dashboards/clusterview.json | 2 +- samples/speedystore/dashboards/detailedclusterviewbynode.json | 2 +- samples/speedystore/dashboards/diskusage.json | 2 +- .../speedystore/dashboards/historicalworkloadmonitoring.json | 2 +- samples/speedystore/dashboards/memoryusage.json | 2 +- samples/speedystore/dashboards/pipelineperformance.json | 2 +- samples/speedystore/dashboards/pipelinesummary.json | 2 +- samples/speedystore/dashboards/queryhistory.json | 2 +- samples/speedystore/dashboards/resourcepoolmonitoring.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/samples/speedystore/dashboards/clusterview.json b/samples/speedystore/dashboards/clusterview.json index 8fbf5d03..fb747717 100644 --- a/samples/speedystore/dashboards/clusterview.json +++ b/samples/speedystore/dashboards/clusterview.json @@ -2443,7 +2443,7 @@ ] }, "timezone": "", - "title": "Cluster View", + "title": "SingleStore: Cluster View", "uid": "detailed-cluster-view2", "version": 1 } diff --git a/samples/speedystore/dashboards/detailedclusterviewbynode.json b/samples/speedystore/dashboards/detailedclusterviewbynode.json index 9b3b1064..b493bca0 100644 --- a/samples/speedystore/dashboards/detailedclusterviewbynode.json +++ b/samples/speedystore/dashboards/detailedclusterviewbynode.json @@ -2477,7 +2477,7 @@ ] }, "timezone": "", - "title": "Detailed Cluster View By Node", + "title": "SingleStore: Detailed Cluster View By Node", "uid": "TVggJLbVk", "version": 1 } diff --git a/samples/speedystore/dashboards/diskusage.json b/samples/speedystore/dashboards/diskusage.json index d657abbf..404babe2 100644 --- a/samples/speedystore/dashboards/diskusage.json +++ b/samples/speedystore/dashboards/diskusage.json @@ -1248,7 +1248,7 @@ "refresh_intervals": [] }, "timezone": "", - "title": "Disk Usage", + "title": "SingleStore: Disk Usage", "uid": "ccd894b4-7e3b-43e0-966b-579ac7eb3714", "version": 1 } diff --git a/samples/speedystore/dashboards/historicalworkloadmonitoring.json b/samples/speedystore/dashboards/historicalworkloadmonitoring.json index bfbf7ae7..21424a62 100644 --- a/samples/speedystore/dashboards/historicalworkloadmonitoring.json +++ b/samples/speedystore/dashboards/historicalworkloadmonitoring.json @@ -1709,7 +1709,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Historical Workload Monitoring", + "title": "SingleStore: Historical Workload Monitoring", "uid": "1xNFf_iSk", "version": 1 } diff --git a/samples/speedystore/dashboards/memoryusage.json b/samples/speedystore/dashboards/memoryusage.json index f577ca05..2f1d6e5c 100644 --- a/samples/speedystore/dashboards/memoryusage.json +++ b/samples/speedystore/dashboards/memoryusage.json @@ -804,7 +804,7 @@ "refresh_intervals": [] }, "timezone": "", - "title": "Memory Usage", + "title": "SingleStore: Memory Usage", "uid": "memory-usage", "version": 1 } diff --git a/samples/speedystore/dashboards/pipelineperformance.json b/samples/speedystore/dashboards/pipelineperformance.json index eeb7d0a7..7ce58cea 100644 --- a/samples/speedystore/dashboards/pipelineperformance.json +++ b/samples/speedystore/dashboards/pipelineperformance.json @@ -1502,7 +1502,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Pipeline Performance", + "title": "SingleStore: Pipeline Performance", "uid": "pipeline-performance", "version": 1 } diff --git a/samples/speedystore/dashboards/pipelinesummary.json b/samples/speedystore/dashboards/pipelinesummary.json index 9026651c..d9d644b3 100644 --- a/samples/speedystore/dashboards/pipelinesummary.json +++ b/samples/speedystore/dashboards/pipelinesummary.json @@ -613,7 +613,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Pipeline Summary", + "title": "SingleStore: Pipeline Summary", "uid": "pipeline-summary", "version": 1 } diff --git a/samples/speedystore/dashboards/queryhistory.json b/samples/speedystore/dashboards/queryhistory.json index 46a6c13c..7ee3832c 100644 --- a/samples/speedystore/dashboards/queryhistory.json +++ b/samples/speedystore/dashboards/queryhistory.json @@ -388,7 +388,7 @@ }, "timepicker": {}, "timezone": "", - "title": "Query History", + "title": "SingleStore: Query History", "uid": "efacc80e-2e33-4bfb-99fe-223b45e4197a", "version": 1 } diff --git a/samples/speedystore/dashboards/resourcepoolmonitoring.json b/samples/speedystore/dashboards/resourcepoolmonitoring.json index f93e0c9b..c53a1e3f 100644 --- a/samples/speedystore/dashboards/resourcepoolmonitoring.json +++ b/samples/speedystore/dashboards/resourcepoolmonitoring.json @@ -711,7 +711,7 @@ ] }, "timezone": "", - "title": "Resource Pool Monitoring", + "title": "SingleStore: Resource Pool Monitoring", "uid": "b706aab4-2dc9-41f0-89c1-2418f8da5005", "version": 1 } From b3a42afc1b0649b3fec67791f119560fcc68dd42 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Thu, 2 Oct 2025 16:57:30 -0400 Subject: [PATCH 09/20] Change datasource name --- .../speedystore/dashboards/clusterview.json | 66 +++++++++--------- .../dashboards/detailedclusterviewbynode.json | 68 +++++++++---------- samples/speedystore/dashboards/diskusage.json | 32 ++++----- .../historicalworkloadmonitoring.json | 34 +++++----- .../speedystore/dashboards/memoryusage.json | 22 +++--- .../dashboards/pipelineperformance.json | 36 +++++----- .../dashboards/pipelinesummary.json | 16 ++--- .../speedystore/dashboards/queryhistory.json | 6 +- .../dashboards/resourcepoolmonitoring.json | 22 +++--- 9 files changed, 151 insertions(+), 151 deletions(-) diff --git a/samples/speedystore/dashboards/clusterview.json b/samples/speedystore/dashboards/clusterview.json index fb747717..2d681deb 100644 --- a/samples/speedystore/dashboards/clusterview.json +++ b/samples/speedystore/dashboards/clusterview.json @@ -68,7 +68,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -192,7 +192,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -245,7 +245,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -351,7 +351,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -403,7 +403,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -493,7 +493,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -558,7 +558,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Number of open connections (threads_connected) to the database relative to the maximum limit (max_connections). If the utilization is near 100%, it means DB is approaching the maximum allowed connections; this can potentially lead to performance issues, as queries may need to wait in a queue until a thread becomes available to process them.", "fieldConfig": { @@ -649,7 +649,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -682,7 +682,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Number of threads actively running queries (threads_running) relative to the maximum limit (max_connection_threads). If the utilization is near 100%, it suggests that the system might be reaching its capacity in terms of how many queries can be executed in parallel. This situation can lead to resource pressure, unresponsiveness, latency spikes, and even failures", "fieldConfig": { @@ -773,7 +773,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -819,7 +819,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -924,7 +924,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -979,7 +979,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1084,7 +1084,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1139,7 +1139,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1243,7 +1243,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1276,7 +1276,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Changes in the pattern of execution time per write query from the historical norm may indicate an issue with your application or changes in your workload.", "fieldConfig": { @@ -1365,7 +1365,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1397,7 +1397,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1502,7 +1502,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1557,7 +1557,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1662,7 +1662,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1717,7 +1717,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1821,7 +1821,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1854,7 +1854,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Changes in the pattern of execution time per read query from the historical norm may indicate an issue with your application or changes in your workload.", "fieldConfig": { @@ -1943,7 +1943,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1975,7 +1975,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -2080,7 +2080,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -2135,7 +2135,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -2240,7 +2240,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -2307,7 +2307,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": false, @@ -2326,7 +2326,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(database_name) from act_samples where $__timeFilter(ts) and (cluster = '$cluster')", "hide": 2, @@ -2348,7 +2348,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "hide": 2, diff --git a/samples/speedystore/dashboards/detailedclusterviewbynode.json b/samples/speedystore/dashboards/detailedclusterviewbynode.json index b493bca0..b1cae738 100644 --- a/samples/speedystore/dashboards/detailedclusterviewbynode.json +++ b/samples/speedystore/dashboards/detailedclusterviewbynode.json @@ -68,7 +68,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -190,7 +190,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -243,7 +243,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -333,7 +333,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -385,7 +385,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -475,7 +475,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -540,7 +540,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Number of open connections (threads_connected) to the database relative to the maximum limit (max_connections). If the utilization is near 100%, it means DB is approaching the maximum allowed connections; this can potentially lead to performance issues, as queries may need to wait in a queue until a thread becomes available to process them.", "fieldConfig": { @@ -663,7 +663,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -716,7 +716,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Number of threads actively running queries (threads_running) relative to the maximum limit (max_connection_threads). If the utilization is near 100%, it suggests that the system might be reaching its capacity in terms of how many queries can be executed in parallel. This situation can lead to resource pressure, unresponsiveness, latency spikes, and even failures", "fieldConfig": { @@ -839,7 +839,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -905,7 +905,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -994,7 +994,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1049,7 +1049,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1138,7 +1138,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1193,7 +1193,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1277,7 +1277,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1332,7 +1332,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Changes in the pattern of execution time per write query from the historical norm may indicate an issue with your application or changes in your workload.", "fieldConfig": { @@ -1418,7 +1418,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1473,7 +1473,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1557,7 +1557,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1612,7 +1612,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1696,7 +1696,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1751,7 +1751,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1835,7 +1835,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1890,7 +1890,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Changes in the pattern of execution time per read query from the historical norm may indicate an issue with your application or changes in your workload.", "fieldConfig": { @@ -1976,7 +1976,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -2031,7 +2031,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -2115,7 +2115,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -2170,7 +2170,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -2254,7 +2254,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -2321,7 +2321,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": false, @@ -2340,7 +2340,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(database_name) from act_samples where $__timeFilter(ts) and (cluster = '$cluster')", "hide": 2, @@ -2362,7 +2362,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": true, @@ -2382,7 +2382,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(port) from metrics where host is not NULL and $__unixEpochFilter(time_sec) and (cluster='$cluster') and (host in ($host) or concat($host) = '%') and port is not null", "includeAll": true, diff --git a/samples/speedystore/dashboards/diskusage.json b/samples/speedystore/dashboards/diskusage.json index 404babe2..305d3b5f 100644 --- a/samples/speedystore/dashboards/diskusage.json +++ b/samples/speedystore/dashboards/diskusage.json @@ -30,7 +30,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -120,7 +120,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -172,7 +172,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -313,7 +313,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -361,7 +361,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -394,7 +394,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Breaksdown consumption of disk by \"Data\" category (in the left graph), adding utilization across all components will be equal to disk utilized by \"Data\"", "fieldConfig": { @@ -535,7 +535,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -568,7 +568,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Breaksdown consumption of disk by databases, adding utilization across all databases will be equal to disk utilized by \"Data\"", "fieldConfig": { @@ -709,7 +709,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -750,7 +750,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "It provides insights into the performance of your SingleStoreDB's blob cache activity. By understanding and monitoring the rate at which the blob cache is downloading files from remote storage, you can identify potential performance bottlenecks or issues related to blob cache activity. \nFor instance: if you observe high download rates given the size of your database and scale of your hardware, you might consider increasing the local cache size.\nBy keeping an eye on this metric, you can make well-informed decisions regarding your cluster's performance and resource allocation to ensure optimal system operation.", "fieldConfig": { @@ -891,7 +891,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -932,7 +932,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "It provides insights into the performance of your SingleStoreDB's blob cache activity. By tracking this metric, you can optimize system resource utilization based on your data management needs. If evictions occur at a high rate, it may indicate that the cache size is too small or that the workload is causing a lot of cache turnover. In such cases, you can take appropriate measures, such as adjusting cache size or reviewing data access patterns, to improve overall cluster performance.\nMonitoring this metric, helps you identify potential performance bottlenecks related to the blob cache and make well-informed decisions for optimizing your SingleStore cluster's performance.", "fieldConfig": { @@ -1073,7 +1073,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1125,7 +1125,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": false, @@ -1143,7 +1143,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(host) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and host is not NULL and host != \"\"", "includeAll": false, @@ -1161,7 +1161,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "hide": 2, diff --git a/samples/speedystore/dashboards/historicalworkloadmonitoring.json b/samples/speedystore/dashboards/historicalworkloadmonitoring.json index 21424a62..e810585d 100644 --- a/samples/speedystore/dashboards/historicalworkloadmonitoring.json +++ b/samples/speedystore/dashboards/historicalworkloadmonitoring.json @@ -43,7 +43,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "", "fieldConfig": { @@ -133,7 +133,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -185,7 +185,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Number of query executions", "fieldConfig": { @@ -274,7 +274,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -336,7 +336,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Time spent running on all the CPUs across the workspace reported by database", "fieldConfig": { @@ -424,7 +424,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -476,7 +476,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "", "fieldConfig": { @@ -564,7 +564,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -616,7 +616,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "", "fieldConfig": { @@ -704,7 +704,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -756,7 +756,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "", "fieldConfig": { @@ -844,7 +844,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -913,7 +913,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Elapsed Time - Wall clock milliseconds elapsed during execution; CPU Time - Milliseconds spent running on all the CPUs across the workspace. This is likely to exceed the observed elapsed time because the tasks are likely to have executed concurrently", "fieldConfig": { @@ -1264,7 +1264,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1424,7 +1424,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(cluster) from `act_samples` where $__timeFilter(ts)", "includeAll": false, @@ -1446,7 +1446,7 @@ ] }, "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(ifnull(database_name,'-')) from `act_samples` where (cluster = '$cluster') and $__timeFilter(ts)", "includeAll": true, @@ -1573,7 +1573,7 @@ "value": "" }, "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select case when '$hidden_activity_name' = 'All' then 'All' else query_text end \nfrom `mv_queries` \nwhere (cluster = '$cluster') and \nactivity_name in ('$hidden_activity_name')", "hide": 2, diff --git a/samples/speedystore/dashboards/memoryusage.json b/samples/speedystore/dashboards/memoryusage.json index 2f1d6e5c..09388de1 100644 --- a/samples/speedystore/dashboards/memoryusage.json +++ b/samples/speedystore/dashboards/memoryusage.json @@ -30,7 +30,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Total_Server_Memory used, out of Maximum_Memory limit.\nUsed memory is broken into data, queries, or internal.", "fieldConfig": { @@ -185,7 +185,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -218,7 +218,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Memory used for query execution, code gen, and plancaching, out of Maximum_Memory limit. Query execution can consume the cache, as well as any available memory less than the total limit.", "fieldConfig": { @@ -350,7 +350,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -383,7 +383,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Table_Memory used, out of Maximum_Table_Memory limit.\nTable_primary and Variable should be the greatest allocators. The others should be small.", "fieldConfig": { @@ -538,7 +538,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -571,7 +571,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "Memory used for internal MemSQL allocations, out of Maximum_Memory limit.\nThe cache holds memory in MemSQL for faster internal allocation (eg for executing queries quickly).", "fieldConfig": { @@ -703,7 +703,7 @@ "alias": "", "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -747,7 +747,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": false, @@ -765,7 +765,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(host) from metrics where cluster = '$cluster' and $__unixEpochFilter(time_sec) and host is not NULL and host != \"\"", "includeAll": false, @@ -783,7 +783,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": false, diff --git a/samples/speedystore/dashboards/pipelineperformance.json b/samples/speedystore/dashboards/pipelineperformance.json index 7ce58cea..b06ab853 100644 --- a/samples/speedystore/dashboards/pipelineperformance.json +++ b/samples/speedystore/dashboards/pipelineperformance.json @@ -55,7 +55,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -140,7 +140,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -212,7 +212,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -281,7 +281,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -368,7 +368,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -458,7 +458,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -545,7 +545,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -635,7 +635,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -722,7 +722,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -812,7 +812,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -899,7 +899,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -989,7 +989,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1076,7 +1076,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -1166,7 +1166,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -1276,7 +1276,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -1372,7 +1372,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(cluster) from pipeline_metrics where $__timeFilter(ts)", "includeAll": false, @@ -1394,7 +1394,7 @@ ] }, "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "SELECT distinct pipeline_name FROM `pipeline_metrics` where $__timeFilter(ts) and cluster = '$cluster'", "includeAll": true, @@ -1414,7 +1414,7 @@ "value": "$__all" }, "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "SELECT distinct database_name FROM `pipeline_metrics` where $__timeFilter(ts) and cluster = '$cluster'", "includeAll": true, diff --git a/samples/speedystore/dashboards/pipelinesummary.json b/samples/speedystore/dashboards/pipelinesummary.json index d9d644b3..beadd3cf 100644 --- a/samples/speedystore/dashboards/pipelinesummary.json +++ b/samples/speedystore/dashboards/pipelinesummary.json @@ -43,7 +43,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -99,7 +99,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -158,7 +158,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -276,7 +276,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "time_series", @@ -330,7 +330,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -410,7 +410,7 @@ { "dataset": "metrics", "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -515,7 +515,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(cluster) from pipeline_metrics where $__timeFilter(ts)", "includeAll": false, @@ -532,7 +532,7 @@ "value": "1693284241" }, "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select UNIX_TIMESTAMP(max(ts)) from pipeline_metrics where $__timeFilter(ts)", "hide": 2, diff --git a/samples/speedystore/dashboards/queryhistory.json b/samples/speedystore/dashboards/queryhistory.json index 7ee3832c..fe535e67 100644 --- a/samples/speedystore/dashboards/queryhistory.json +++ b/samples/speedystore/dashboards/queryhistory.json @@ -43,7 +43,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "description": "", "fieldConfig": { @@ -276,7 +276,7 @@ "targets": [ { "datasource": { - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -369,7 +369,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct(cluster) from `query_event_history` where $__timeFilter(ts)", "includeAll": false, diff --git a/samples/speedystore/dashboards/resourcepoolmonitoring.json b/samples/speedystore/dashboards/resourcepoolmonitoring.json index c53a1e3f..94bb9f7a 100644 --- a/samples/speedystore/dashboards/resourcepoolmonitoring.json +++ b/samples/speedystore/dashboards/resourcepoolmonitoring.json @@ -55,7 +55,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -142,7 +142,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -182,7 +182,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -269,7 +269,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -309,7 +309,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -396,7 +396,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -436,7 +436,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "fieldConfig": { "defaults": { @@ -523,7 +523,7 @@ { "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "editorMode": "code", "format": "table", @@ -575,7 +575,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "includeAll": false, @@ -594,7 +594,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "select distinct labels::$pool_name\nfrom metrics\nwhere name = 'memsql_resource_pool_status_finished_queries' and\n $__unixEpochFilter(time_sec) and (cluster='$cluster')", "includeAll": true, @@ -616,7 +616,7 @@ }, "datasource": { "type": "mysql", - "uid": "monitoring" + "uid": "s2monitoring" }, "definition": "", "hide": 2, From 4840aa7b7b1754ae7e9119d4b2c4c8a1f9b0e09e Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Thu, 2 Oct 2025 17:00:20 -0400 Subject: [PATCH 10/20] Correct namespace for datasource secret --- samples/speedystore/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index fc6e45a6..6350aa73 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -137,13 +137,15 @@ Copy the file to some location, update the necessary information and save your c Then submit the following command to create the datasource: -`kubectl -n $VIYA_NS create secret generic grafana-metrics-connection --from-file=$USER_DIR/monitoring/speedystore-datasource.yaml` +`kubectl -n monitoring create secret generic grafana-metrics-connection --from-file=$USER_DIR/monitoring/speedystore-datasource.yaml` + +NOTE: This command assumes the metric monitoring components (including Grafana) have been deployed into the `monitoring` namespace. If they are deployed in a different namespace, update the command to reference to correct namespace. After secret has been created, you need to apply a specific label to the secret to trigger the automatic provisioning (Ioading) of the datasource into Grafana. You can use the following command to apply the necessary label: -`kubectl -n $VIYA_NS label secret grafana-metrics-connection "grafana_datasource=1"` +`kubectl -n monitoring label secret grafana-metrics-connection "grafana_datasource=1"` ### Import the SingleStore Dashboards into Grafana From 335a770ffbe140025faf4aa301850f03a10e584d Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Thu, 2 Oct 2025 18:19:34 -0400 Subject: [PATCH 11/20] Tweaked README --- samples/speedystore/README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 6350aa73..86f2f0bc 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -26,6 +26,8 @@ The diagram below, taken from the [SingleStore documentation](https://docs.singl The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. +>**NOTE: The SingleStore Toolbox must be installed on a host that can access the SingleStore cluster pods using the internal cluster hostnames and IP addresses. This can be a jump box (bastion) host or, if necessary, one of the Kubernetes cluster nodes. In addition to the SingleStore Toolbox, you must be able to submit `kubectl` commands from this host.** + To configure and start the monitoring, including the metrics database, the following command will (eventually) be submitted: `sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` @@ -59,7 +61,7 @@ You will need the password for the SingleStore 'root' user. You can use the fol `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter -As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You will need to provide the fully-qualified host name or IP address for the exporter host. And the name needs to be resolvable by the host running the `sdb-admin` command. Since the fully-qualified host name may not be resolvable, we will use the IP address for the `exporter-host` parameter instead. +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You will need to provide the fully-qualified host name or IP address for the exporter host. And, as noted above, the IP address or host name needs to be resolvable by the host running the `sdb-admin` command. This example uses an IP address for the `exporter-host` parameter. You can obtain the IP address for the Master node and stored it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: @@ -96,7 +98,7 @@ Once completed, the exporter process, the pipeline and the metrics database have ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) ### Create the "S2MonitorUser" -You need to create a specific user that Grafana can use to connect to the ***'metrics'*** database. While the permissions required by this user to pull metrics from the database are fairly limited, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. +You need to create a specific user that Grafana can use to connect to the ***'metrics'*** database. After logging into SingleStore with the admin user, you can submit `CREATE USER` and `GRANT` commands to create the user and grant the user the desired permissions. @@ -104,17 +106,19 @@ For example, the following command creates a user called `S2MonitorUser` and set `CREATE USER S2MonitorUser IDENTIFIED BY 'password123' REQUIRE NONE;` -Then you can grant the desired permissions by submitting the following commands: +The following command grants a minimal set of permissions that allows the newly created user to access the collected metrics and populate the Grafana dashboards: -`GRANT CLUSTER, SHOW METADATA, SELECT, PROCESS ON *.* to 'S2MonitorUser'@'%';` +`GRANT SELECT, SHOW VIEW ON metrics.* to 'S2MonitorUser'@'%';` -`GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to 'S2MonitorUser'@'%';` +Alternatively, while the limited permissions above are sufficient to pull metrics from the database, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. -Alternatively, you could GRANT the "monitoring user" minimal permissions, and create a second user ("monitoring administrator") to manage the metrics database, pipelines and the exporter process. +The following commands grant a broader set of permissions to allow the monitoring user to perform these administrator duties: -|**TO DO: Does the first GRANT statement only grant the _minimal_ permissions needed to pull metirics? And the 2nd grants the extended permissions needed to be an administrator?** +`GRANT CLUSTER, SHOW METADATA, SELECT, PROCESS ON *.* to 'S2MonitorUser'@'%';` -|**TO DO: Is the user name *S2MonitorUser*?** +`GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to 'S2MonitorUser'@'%';` + +You should consider your organization's specific needs before deciding whether to grant the more limited or broader set of permissions to this user. ### Configure the Grafana Datasource Grafana datasources provide connection information allowing Grafana to access metric information in response to user queries and to populate dashboards. @@ -129,8 +133,6 @@ to: `url: svc-sas-singlestore-cluster-ddl.myviya.svc.cluster.local:3306` -|**TO DO**: Is the service-name always _name_of_singlestore_cluster_ + "-dll" - If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update that portion of the ***url*** field in the file as well. Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. This will ensure all of the files related to this deployment of SAS Viya Monitoring are in one place. From 470d6530d047d5e8420a893fc9881fc56f263c49 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Thu, 2 Oct 2025 18:33:23 -0400 Subject: [PATCH 12/20] tweak README, add prune to datasource --- samples/speedystore/README.md | 2 +- samples/speedystore/speedystore-datasource.yaml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 86f2f0bc..791615d2 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -26,7 +26,7 @@ The diagram below, taken from the [SingleStore documentation](https://docs.singl The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. ->**NOTE: The SingleStore Toolbox must be installed on a host that can access the SingleStore cluster pods using the internal cluster hostnames and IP addresses. This can be a jump box (bastion) host or, if necessary, one of the Kubernetes cluster nodes. In addition to the SingleStore Toolbox, you must be able to submit `kubectl` commands from this host.** +>**NOTE: The SingleStore Toolbox must be installed on a host that can access the SingleStore cluster pods using the internal cluster hostnames and IP addresses. This can be a jump box (bastion) host or, if necessary, one of the Kubernetes cluster nodes. In addition to the SingleStore Toolbox, you must be able to submit `kubectl` commands from this host as well.** To configure and start the monitoring, including the metrics database, the following command will (eventually) be submitted: diff --git a/samples/speedystore/speedystore-datasource.yaml b/samples/speedystore/speedystore-datasource.yaml index 7e15c3a6..1d0a2b7f 100644 --- a/samples/speedystore/speedystore-datasource.yaml +++ b/samples/speedystore/speedystore-datasource.yaml @@ -1,7 +1,9 @@ apiVersion: 1 - +deleteDatasources: +- name: s2monitoring +prune: true datasources: - - name: monitoring + - name: s2monitoring type: mysql url: svc-sas-singlestore-cluster-ddl.VIYA_NS.svc.cluster.local:3306 database: metrics From e11ef1d06caea3b1598c2799b24e4d79be31c990 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Fri, 3 Oct 2025 15:21:38 -0400 Subject: [PATCH 13/20] Final (?) tweaks --- samples/speedystore/README.md | 68 ++++++++++++------- .../speedystore/speedystore-datasource.yaml | 4 +- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 791615d2..29bbe9b4 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -15,6 +15,7 @@ The diagram below, taken from the [SingleStore documentation](https://docs.singl ![Overview of SingleStore Monitoring Process ](images/cluster_monitoring_hl_architecture-mfjdOm.webp) ### Overview of Process +* Prerequisites and Set-Up * Configure SingleStore * Create the SingleStore pipeline and metrics database * Create the "S2MonitorUser" user @@ -22,17 +23,20 @@ The diagram below, taken from the [SingleStore documentation](https://docs.singl * Create the datasource * Import the SingleStore dashboards -### Create the SingleStore pipeline and metrics database +### Prerequisites and Set-Up +#### Prerequisites +* SingleStore Toolbox -The SingleStore Toolbox is used to deploy, administer, and manage a SingleStore cluster. The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. +You will need to use the SingleStore Toolbox package to deploy, administer, and manage a SingleStore cluster. [Installation instructions for SingleStore Toolbox](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-management-with-tools/singlestore-tools-installation/singlestore-toolbox-installation/) are available on the SingleStore website. ->**NOTE: The SingleStore Toolbox must be installed on a host that can access the SingleStore cluster pods using the internal cluster hostnames and IP addresses. This can be a jump box (bastion) host or, if necessary, one of the Kubernetes cluster nodes. In addition to the SingleStore Toolbox, you must be able to submit `kubectl` commands from this host as well.** +* SingleStore CLI or SingleStore Studio -To configure and start the monitoring, including the metrics database, the following command will (eventually) be submitted: +You will need to use submit database commands via the SingleStore CLI to create a database user and grant them the appropriate permissions. [Installation instructions for SingleStore CLI](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-management-with-tools/singlestore-tools-installation/singlestore-client-installation/) are available on the SingleStore website. -`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` +Or, alternatively, you can submit the necessary commands via the SingleStore Studio SQL Editor panel. +* `kubectl` -But, before submitting the command, the various parameters being passed to the command and how to determine their proper values will be reviewed. +You will need to use `kubectl` commands to obtain information about the your SAS Viya and SingleStore deployments. #### Set the VIYA_NS environent variable @@ -40,7 +44,18 @@ Since you will need to refer repeatedly to the namespace in which SAS Viya (and In the following command, the `VIYA_NS` environment variable is defined and assigned the value identifying the namespace containing our SAS Viya deployment (i.e. ***myviya*** ): - `export VIYA_NS=myviya` + `VIYA_NS=myviya` + +### Configure SingleStore +#### Create the SingleStore pipeline and metrics database +The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. + +To configure and start the monitoring, including the metrics database, the following command will (eventually) be submitted: + +`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` + +But, before submitting the command, the various parameters being passed to the command and how to determine their proper values will be reviewed. + #### The `cluster-name` parameter The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: ***sas-singlestore-cluster***. However, since it is possible to change this name, it is important to confirm the actual cluster name before configuring the monitoring. @@ -54,14 +69,14 @@ If the cluster name is different than the default, be sure to use the correct va #### The `user` and `password` parameters A core part of the monitoring is the exporter process which collects the metric data from the cluster. The exporter process is typically run as the SingleStore 'root' user due to the permissions required. -NOTE: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user is out-of-scope for this sample and we will use the 'root' user. +NOTE: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user for this is out-of-scope for this sample and we will use the 'root' user. You will need the password for the SingleStore 'root' user. You can use the following command to get the password for the 'root' user and store it in the `ROOT_PWD` environment variable: `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter -As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. You will need to provide the fully-qualified host name or IP address for the exporter host. And, as noted above, the IP address or host name needs to be resolvable by the host running the `sdb-admin` command. This example uses an IP address for the `exporter-host` parameter. +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. This example you will use that pod's IP address for the `exporter-host` parameter. You can obtain the IP address for the Master node and stored it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: @@ -94,13 +109,11 @@ Automatically selected yes, non-interactive mode enabled Operation completed successfully ``` -Once completed, the exporter process, the pipeline and the metrics database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created **'metrics'** database: +Once completed, the exporter process, the pipeline and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created `**metrics**' database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) ### Create the "S2MonitorUser" -You need to create a specific user that Grafana can use to connect to the ***'metrics'*** database. - -After logging into SingleStore with the admin user, you can submit `CREATE USER` and `GRANT` commands to create the user and grant the user the desired permissions. +Next, you need to create a specific user that Grafana can use to connect to the '**metrics**' database. After logging into SingleStore with the admin user, you can submit the `CREATE USER` and `GRANT` commands via the SingleStore CLI (or, from the SQL Editor within SingleStore Studio) to create the user and grant the user the desired permissions. For example, the following command creates a user called `S2MonitorUser` and sets its password: @@ -108,7 +121,7 @@ For example, the following command creates a user called `S2MonitorUser` and set The following command grants a minimal set of permissions that allows the newly created user to access the collected metrics and populate the Grafana dashboards: -`GRANT SELECT, SHOW VIEW ON metrics.* to 'S2MonitorUser'@'%';` +`GRANT SELECT, SHOW VIEW, EXECUTE ON metrics.* TO 'S2MonitorUser'@'%'` Alternatively, while the limited permissions above are sufficient to pull metrics from the database, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. @@ -118,16 +131,16 @@ The following commands grant a broader set of permissions to allow the monitorin `GRANT SELECT, CREATE, INSERT, UPDATE, DELETE, EXECUTE, INDEX, ALTER, DROP, CREATE DATABASE, LOCK TABLES, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, CREATE PIPELINE, DROP PIPELINE, ALTER PIPELINE, START PIPELINE, SHOW PIPELINE ON metrics.* to 'S2MonitorUser'@'%';` -You should consider your organization's specific needs before deciding whether to grant the more limited or broader set of permissions to this user. - -### Configure the Grafana Datasource +You should consider your organization's specific needs before deciding whether to grant the more limited or the broader set of permissions to this user. +### Configure Grafana +#### Configure the Grafana Datasource Grafana datasources provide connection information allowing Grafana to access metric information in response to user queries and to populate dashboards. -The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the ***'metrics'*** database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You will also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. +The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the '**metrics**' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You will also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. For example, if SAS Viya is deployed into the ***myviya*** namespace, you would revise the ***url*** value from: -`url: svc-sas-singlestore-cluster-ddl.VIYA_NS.svc.cluster.local:3306` +`svc-sas-singlestore-cluster-ddl.{**Replace with SAS VIYA Namespace**}.svc.cluster.local:3306` to: @@ -139,18 +152,18 @@ Copy the file to some location, update the necessary information and save your c Then submit the following command to create the datasource: -`kubectl -n monitoring create secret generic grafana-metrics-connection --from-file=$USER_DIR/monitoring/speedystore-datasource.yaml` +`kubectl -n monitoring create secret generic grafana-speedystore-connection --from-file=$USER_DIR/monitoring/speedystore-datasource.yaml` NOTE: This command assumes the metric monitoring components (including Grafana) have been deployed into the `monitoring` namespace. If they are deployed in a different namespace, update the command to reference to correct namespace. -After secret has been created, you need to apply a specific label to the secret to trigger the automatic provisioning (Ioading) of the datasource into Grafana. +After secret has been created, you need to apply a specific label to the secret to trigger the automatic provisioning (loading) of the datasource into Grafana. You can use the following command to apply the necessary label: -`kubectl -n monitoring label secret grafana-metrics-connection "grafana_datasource=1"` +`kubectl -n monitoring label secret grafana-speedystore-connection "grafana_datasource=1"` -### Import the SingleStore Dashboards into Grafana +#### Import the SingleStore Dashboards into Grafana To import the SingleStore dashboards into Grafana, you can use the `deploy_dashboards.sh` script found in the `monitoring/bin` sub-directory of this repository. You can use the following command to import all of the SingleStore dashboards: @@ -162,9 +175,9 @@ Or, you can import specific dashboards individually using the same script. For `./monitoring/bin/deploy_dashboards.sh samples/speedystore/dashboards/clusterview.yaml` ### Validate -Once the dashboards have been imported into Grafana, you should be ready to monitor the SingleStore instance embedded in SAS SpeedyStore. +Once the dashboards have been imported into Grafana, you should be all set to monitor the SingleStore instance embedded in SAS SpeedyStore. -To validate the configuration, sign into Grafana and review each of the SingleStore dashboards you've imported. All of the imported dashboards have the ***"sas-speedystore"*** and ***"singlestore"*** tags. While the data shown will vary based on user activity, all of the dashboards should be available with no errors or warning icons or messages. +To validate the configuration, sign into Grafana and review the SingleStore dashboards you've imported. All of the imported dashboards have the ***"sas-speedystore"*** and ***"singlestore"*** tags. While the data shown will vary based on user activity, all of the dashboards should be available with no errors or warning icons or messages. ## The Grafana Dashboards This is a list of the SingleStore dashboards included in this sample. Each dashboard name in the list is a link to more information about the dashboard in the SingleStore documentation including the metrics depicted and the types of questions they address. @@ -182,8 +195,11 @@ This is a list of the SingleStore dashboards included in this sample. Each das Thank you to Michael Goddard (SAS Education) for all of his work sorting this out and allowing us to share it here. ## References +[Blog Post: Using Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) + +[Workshop: SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) + [SingleStore Documentation: Configure Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/) [SingleStore Documentation: Detailed Discussion of each dashboard including metrics shown and when to use them](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/) - diff --git a/samples/speedystore/speedystore-datasource.yaml b/samples/speedystore/speedystore-datasource.yaml index 1d0a2b7f..e89b04af 100644 --- a/samples/speedystore/speedystore-datasource.yaml +++ b/samples/speedystore/speedystore-datasource.yaml @@ -5,10 +5,10 @@ prune: true datasources: - name: s2monitoring type: mysql - url: svc-sas-singlestore-cluster-ddl.VIYA_NS.svc.cluster.local:3306 + url: svc-sas-singlestore-cluster-ddl.{**Replace with SAS VIYA Namespace**}.svc.cluster.local:3306 database: metrics user: S2MonitorUser secureJsonData: - password: {Monitoring_User_Password} + password: {**Replace with S2MonitorUser Password**} isDefault: false version: 1 \ No newline at end of file From e2afc72284d04551ec2fab8046bef9f32cf5b94a Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Fri, 3 Oct 2025 17:21:57 -0400 Subject: [PATCH 14/20] Tweaks to README --- samples/speedystore/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 29bbe9b4..4edc8b23 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -112,7 +112,7 @@ Operation completed successfully Once completed, the exporter process, the pipeline and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created `**metrics**' database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) -### Create the "S2MonitorUser" +### Create the "S2MonitorUser" user Next, you need to create a specific user that Grafana can use to connect to the '**metrics**' database. After logging into SingleStore with the admin user, you can submit the `CREATE USER` and `GRANT` commands via the SingleStore CLI (or, from the SQL Editor within SingleStore Studio) to create the user and grant the user the desired permissions. For example, the following command creates a user called `S2MonitorUser` and sets its password: @@ -174,13 +174,14 @@ Or, you can import specific dashboards individually using the same script. For `./monitoring/bin/deploy_dashboards.sh samples/speedystore/dashboards/clusterview.yaml` -### Validate +### Validate everything is working Once the dashboards have been imported into Grafana, you should be all set to monitor the SingleStore instance embedded in SAS SpeedyStore. To validate the configuration, sign into Grafana and review the SingleStore dashboards you've imported. All of the imported dashboards have the ***"sas-speedystore"*** and ***"singlestore"*** tags. While the data shown will vary based on user activity, all of the dashboards should be available with no errors or warning icons or messages. ## The Grafana Dashboards This is a list of the SingleStore dashboards included in this sample. Each dashboard name in the list is a link to more information about the dashboard in the SingleStore documentation including the metrics depicted and the types of questions they address. + * [Cluster View](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#cluster-view) * [Detailed Cluster View by Node](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#detailed-cluster-view-by-node) * [Disk Usage](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#disk-usage) @@ -191,6 +192,10 @@ This is a list of the SingleStore dashboards included in this sample. Each das * [Query History](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#query-history) * [Resource Pool Monitoring](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/view-the-dashboards/#resource-pool-monitoring) +NOTE: The following modifications have been made to the original SingleStore dashboards definitions: +* the json files were renamed to use all lowercase and remove spaces; +* the name of the datasource was changed from `monitoring` to `s2monitoring`; and, +* the tags `sas-speedystore` and `singlestore` were added to the dashboards. ## Acknowledgements Thank you to Michael Goddard (SAS Education) for all of his work sorting this out and allowing us to share it here. From 74ffc4c3697432a475f370151e6ad819c9920738 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:36:40 -0400 Subject: [PATCH 15/20] Update README.md based on review comments --- samples/speedystore/README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 4edc8b23..ac277b3b 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -5,10 +5,10 @@ This sample demonstrates how to extend SAS Viya Monitoring for Kubernetes to mon This sample is primarily derived from the blog post [Using Grafana dashboards for monitoring SAS SpeedyStore](https://communities.sas.com/t5/SAS-Communities-Library/Using-Grafana-dashboards-for-monitoring-SAS-SpeedyStore/ta-p/973178) written by Michael Goddard from SAS Education. The blog post was, in turn, based on work Michael did in preparing to cover the topic as part of the [SAS® SpeedyStore: Architect and Deploy the SAS® Viya® Platform with SingleStore](https://learn.sas.com/course/view.php?id=6393) workshop available in [learn.sas.com](https://learn.sas.com/). This sample includes Grafana dashboards developed and made available by SingleStore. -**Note: There may be other ways to achieve these same objectives, this sample documents one possible approach.** +**Note: This sample documents one possible approach, there might be other ways to achieve the same objectives.** ## Using this Sample -Enabling this monitoring will required configuring components in both SingleStore and Grafana. While this sample describes how to configure the SingleStore components, you are strongly encouraged to review the official SingleStore documentation for a more comprehensive discussion of how to monitor SingleStore effectively, the options for doing so and additional implementation details. After configuring the SingleStore components, this sample covers defining the datasource within Grafana and deploying the SingleStore-specific Grafana dashboards. +Enabling this monitoring will required configuring components in both SingleStore and Grafana. While this sample describes how to configure the SingleStore components, you are strongly encouraged to review the official SingleStore documentation for a more comprehensive discussion of how to monitor SingleStore effectively, the options for doing so, and additional implementation details. After configuring the SingleStore components, this sample covers defining the datasource within Grafana and deploying the SingleStore-specific Grafana dashboards. The diagram below, taken from the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/user-and-cluster-administration/cluster-health-and-performance/configure-monitoring/), provides a high-level overview of metric collection and reporting process. As shown, the SingleStore pipeline extracts metrics from the SingleStore cluster and stores them within a metrics database. Grafana pulls metric data directly from this metrics database to populate the dashboards administrators view. @@ -36,7 +36,7 @@ You will need to use submit database commands via the SingleStore CLI to create Or, alternatively, you can submit the necessary commands via the SingleStore Studio SQL Editor panel. * `kubectl` -You will need to use `kubectl` commands to obtain information about the your SAS Viya and SingleStore deployments. +You will need to use `kubectl` commands to obtain information about your SAS Viya and SingleStore deployments. #### Set the VIYA_NS environent variable @@ -50,11 +50,11 @@ In the following command, the `VIYA_NS` environment variable is defined and assi #### Create the SingleStore pipeline and metrics database The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. -To configure and start the monitoring, including the metrics database, the following command will (eventually) be submitted: +To configure and start the monitoring, including the metrics database, the following command will be used: `sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` -But, before submitting the command, the various parameters being passed to the command and how to determine their proper values will be reviewed. +Before submitting the command, the various parameters being passed to the command and how to determine their proper values will be reviewed. #### The `cluster-name` parameter @@ -76,9 +76,9 @@ You will need the password for the SingleStore 'root' user. You can use the fol `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter -As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. This example you will use that pod's IP address for the `exporter-host` parameter. +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. In this example you will use that pod's IP address for the `exporter-host` parameter. -You can obtain the IP address for the Master node and stored it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: +You can obtain the IP address for the Master node and store it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: `CLUSTER_MASTER_IP=$(kubectl -n ${VIYA_NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` @@ -86,7 +86,7 @@ You can obtain the IP address for the Master node and stored it in the `CLUSTER_ By default, the `sdb-admin start-monitoring-kube` command will display some information and ask the user if they would like to continue. To skip this prompt and have the configuration continue automatically, include the `--yes` parameter. #### Accessing the Kubernetess Cluster -The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will use the file identified in the `KUBECONFIG` environment variable or the `~/.kube/config` file are used to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config file. +The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will attempt to use the file identified in the `KUBECONFIG` environment variable, if defined, or the `~/.kube/config` file, if it exists, to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config file to use. #### Run the `sb-admin start-monitoring-kube` command After setting all of the required parameters, submit the following command to configure and start the monitoring, including the metrics database: @@ -109,7 +109,7 @@ Automatically selected yes, non-interactive mode enabled Operation completed successfully ``` -Once completed, the exporter process, the pipeline and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created `**metrics**' database: +Once completed, the exporter process, the pipeline, and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created `**metrics**' database: ![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) ### Create the "S2MonitorUser" user @@ -123,7 +123,7 @@ The following command grants a minimal set of permissions that allows the newly `GRANT SELECT, SHOW VIEW, EXECUTE ON metrics.* TO 'S2MonitorUser'@'%'` -Alternatively, while the limited permissions above are sufficient to pull metrics from the database, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines and the exporter process. +Alternatively, while the limited permissions above are sufficient to pull metrics from the database, it can be helpful to grant additional permissions so this same user can be used to manage the metrics database, pipelines, and the exporter process. The following commands grant a broader set of permissions to allow the monitoring user to perform these administrator duties: @@ -148,15 +148,15 @@ to: If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update that portion of the ***url*** field in the file as well. -Copy the file to some location, update the necessary information and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. This will ensure all of the files related to this deployment of SAS Viya Monitoring are in one place. +Copy the file to some location, update the necessary information, and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. This will ensure all of the files related to this deployment of SAS Viya Monitoring are in one place. Then submit the following command to create the datasource: `kubectl -n monitoring create secret generic grafana-speedystore-connection --from-file=$USER_DIR/monitoring/speedystore-datasource.yaml` -NOTE: This command assumes the metric monitoring components (including Grafana) have been deployed into the `monitoring` namespace. If they are deployed in a different namespace, update the command to reference to correct namespace. +NOTE: This command assumes the metric monitoring components (including Grafana) have been deployed into the `monitoring` namespace. If they are deployed in a different namespace, update the command to reference the correct namespace. -After secret has been created, you need to apply a specific label to the secret to trigger the automatic provisioning (loading) of the datasource into Grafana. +After the secret has been created, you need to apply a specific label to the secret to trigger the automatic provisioning (loading) of the datasource into Grafana. You can use the following command to apply the necessary label: From 880b00f41963d4aa27f00c3e9d0064b7b8184501 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:51:36 -0400 Subject: [PATCH 16/20] Tweak README --- samples/speedystore/README.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index ac277b3b..6a214c78 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -50,12 +50,7 @@ In the following command, the `VIYA_NS` environment variable is defined and assi #### Create the SingleStore pipeline and metrics database The `sdb-admin start-monitoring-kube` command is used to configure and start the monitoring. It has a number of flags to control its operations. See the [SingleStore documentation](https://docs.singlestore.com/db/v8.9/reference/singlestore-tools-reference/sdb-admin-commands/start-monitoring-kube/) for more information. -To configure and start the monitoring, including the metrics database, the following command will be used: - -`sdb-admin start-monitoring-kube --cluster-name sas-singlestore-cluster --namespace $VIYA_NS --user root --password $ROOT_PWD --exporter-host $CLUSTER_MASTER_IP` - -Before submitting the command, the various parameters being passed to the command and how to determine their proper values will be reviewed. - +Before submitting the `sdb-admin start-monitoring-kube` command, the various parameters being passed to the command and how to determine their proper values will be reviewed. #### The `cluster-name` parameter The default name for the SingleStore cluster in a SAS SpeedyStore deployment is: ***sas-singlestore-cluster***. However, since it is possible to change this name, it is important to confirm the actual cluster name before configuring the monitoring. @@ -71,22 +66,22 @@ A core part of the monitoring is the exporter process which collects the metric NOTE: It is possible to run the process as another user but the user must have the low level permissions needed to create and control the metrics database and pipelines. Setting up an alternate user for this is out-of-scope for this sample and we will use the 'root' user. -You will need the password for the SingleStore 'root' user. You can use the following command to get the password for the 'root' user and store it in the `ROOT_PWD` environment variable: +You need the password for the SingleStore 'root' user. You can use the following command to get the password for the 'root' user and store it in the `ROOT_PWD` environment variable: `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter -As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. In this example you will use that pod's IP address for the `exporter-host` parameter. +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. In this example, that pod's IP address will be used for the `exporter-host` parameter. You can obtain the IP address for the Master node and store it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: `CLUSTER_MASTER_IP=$(kubectl -n ${VIYA_NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` #### Disabling interactive mode -By default, the `sdb-admin start-monitoring-kube` command will display some information and ask the user if they would like to continue. To skip this prompt and have the configuration continue automatically, include the `--yes` parameter. +By default, the `sdb-admin start-monitoring-kube` command displays some information and asks the user if they would like to continue. To skip this prompt and have the configuration continue automatically, this example includes the `--yes` parameter. #### Accessing the Kubernetess Cluster -The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command will attempt to use the file identified in the `KUBECONFIG` environment variable, if defined, or the `~/.kube/config` file, if it exists, to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config file to use. +The `sb-admin` command needs to access the Kubernetes cluster on which SAS Viya and SingleStore are running. It does this through a Kubernetes configuration file. By default, the command uses the file identified in the `KUBECONFIG` environment variable (if defined), or the `~/.kube/config` file (if it exists) to discover the cluster. Alternatively, the `--config-file` option can be used to specify the kube config file to use. #### Run the `sb-admin start-monitoring-kube` command After setting all of the required parameters, submit the following command to configure and start the monitoring, including the metrics database: @@ -136,7 +131,7 @@ You should consider your organization's specific needs before deciding whether t #### Configure the Grafana Datasource Grafana datasources provide connection information allowing Grafana to access metric information in response to user queries and to populate dashboards. -The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the '**metrics**' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You will also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. +The file [speedystore-datasource.yaml](speedystore-datasource.yaml) in this directory defines the datasource that will allow Grafana to access the '**metrics**' database created above. However, before it can be used, it needs to be edited to provide the proper credentials (i.e. the ***user*** and ***password*** fields in the file). You also need to update the ***url*** field to reflect the namespace in which SAS Viya deployment is deployed. For example, if SAS Viya is deployed into the ***myviya*** namespace, you would revise the ***url*** value from: @@ -146,7 +141,7 @@ to: `url: svc-sas-singlestore-cluster-ddl.myviya.svc.cluster.local:3306` - If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you will need to update that portion of the ***url*** field in the file as well. + If the name of the SingleStore cluster is not ***sas-singlestore-cluster***, you need to update that portion of the ***url*** field in the file as well. Copy the file to some location, update the necessary information, and save your changes. We suggest copying the file into your `$USER_DIR/monitoring` sub-directory, i.e. the same directory used for any other customizations related to the metric monitoring components you have made to your deployment of SAS Viya Monitoring. This will ensure all of the files related to this deployment of SAS Viya Monitoring are in one place. From 3088bac8f8afd94e1caef0aeb68458a6d7bfb9c5 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:23:46 -0400 Subject: [PATCH 17/20] README tweaks based on testing --- samples/speedystore/README.md | 15 +++++++++++---- .../images/singlestore_studio-database.png | Bin 0 -> 129615 bytes .../images/singlestore_studio-pipelines.png | Bin 0 -> 95431 bytes 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 samples/speedystore/images/singlestore_studio-database.png create mode 100644 samples/speedystore/images/singlestore_studio-pipelines.png diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index 6a214c78..d6a590df 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -71,9 +71,11 @@ You need the password for the SingleStore 'root' user. You can use the followin `ROOT_PWD=$(kubectl -n ${VIYA_NS} get secret sas-singlestore-cluster -o yaml | grep "ROOT_PASSWORD"|awk '{print $2}'|base64 -d --wrap=0)` #### The `exporter-host` parameter -As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** node (pod) in a SAS SpeedyStore deployment. In this example, that pod's IP address will be used for the `exporter-host` parameter. +As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** pod in a SAS SpeedyStore deployment. -You can obtain the IP address for the Master node and store it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: +>NOTE: The wording here can be a bit confusing: the _SingleStore Master node_ is a specific Kubernetes pod, it is __not__ a _Kubernetes cluster master node_, which is a node (host) in the Kubernetes control plane. + +In this example, the SingleStore Master node (pod) IP address will be used for the `exporter-host` parameter. You can obtain the pod's IP address and store it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: `CLUSTER_MASTER_IP=$(kubectl -n ${VIYA_NS} get pods -o wide | grep 'node-sas-singlestore-cluster-master-0' | awk '{print $6}')` @@ -104,8 +106,13 @@ Automatically selected yes, non-interactive mode enabled Operation completed successfully ``` -Once completed, the exporter process, the pipeline, and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. For example, in the screenshot below, you can see the newly created `**metrics**' database: -![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/02_MG_202508_metrics-database.png) +Once completed, the exporter process, the pipeline, and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. + +For example, in the screenshots below, you can see the newly created piplelines are up and the `**metrics**' database exists: + +![Screenshot showing SingleStore Studio with the pipelines highlighted](images/singlestore_studio-pipelines.png) + +![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/singlestore_studio-database.png) ### Create the "S2MonitorUser" user Next, you need to create a specific user that Grafana can use to connect to the '**metrics**' database. After logging into SingleStore with the admin user, you can submit the `CREATE USER` and `GRANT` commands via the SingleStore CLI (or, from the SQL Editor within SingleStore Studio) to create the user and grant the user the desired permissions. diff --git a/samples/speedystore/images/singlestore_studio-database.png b/samples/speedystore/images/singlestore_studio-database.png new file mode 100644 index 0000000000000000000000000000000000000000..12e94e373112381b6d1c062b92437111b5d8ffc6 GIT binary patch literal 129615 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

*B#uh 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%0Dp&d{q*j2(; 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 z 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 literal 0 HcmV?d00001 diff --git a/samples/speedystore/images/singlestore_studio-pipelines.png b/samples/speedystore/images/singlestore_studio-pipelines.png new file mode 100644 index 0000000000000000000000000000000000000000..105bf04ba73476d64fe859e8e7997186f4e37fca GIT binary patch literal 95431 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%0D(6K9!WfK`c;G5a73{$gqV~6y8 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 Date: Tue, 7 Oct 2025 17:29:41 -0400 Subject: [PATCH 18/20] minor tweak in wording --- samples/speedystore/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/speedystore/README.md b/samples/speedystore/README.md index d6a590df..48c6f21f 100644 --- a/samples/speedystore/README.md +++ b/samples/speedystore/README.md @@ -73,7 +73,7 @@ You need the password for the SingleStore 'root' user. You can use the followin #### The `exporter-host` parameter As shown in the diagram above, the export process runs on the Master Aggregator. Therefore, you need to target the SingleStore Master node; i.e. the **node-sas-singlestore-cluster-master-0** pod in a SAS SpeedyStore deployment. ->NOTE: The wording here can be a bit confusing: the _SingleStore Master node_ is a specific Kubernetes pod, it is __not__ a _Kubernetes cluster master node_, which is a node (host) in the Kubernetes control plane. +>NOTE: The wording here can be a bit confusing: the SingleStore _Master node_ is a specific Kubernetes pod, it is __not__ a Kubernetes _cluster master node_, which is a node (host) in the Kubernetes control plane. In this example, the SingleStore Master node (pod) IP address will be used for the `exporter-host` parameter. You can obtain the pod's IP address and store it in the `CLUSTER_MASTER_IP` environment variable by submitting the following command: @@ -108,11 +108,11 @@ Operation completed successfully Once completed, the exporter process, the pipeline, and the '**metrics**' database have been created. You can use the SingleStore Studio, to confirm this. -For example, in the screenshots below, you can see the newly created piplelines are up and the `**metrics**' database exists: +For example, in the screenshots below, the newly created piplelines are up and the `**metrics**' database exists: -![Screenshot showing SingleStore Studio with the pipelines highlighted](images/singlestore_studio-pipelines.png) +![Screenshot showing SingleStore Studio with arrow pointing to the new pipelines](images/singlestore_studio-pipelines.png) -![Screenshot showing SingleStore Studio with the 'metrics' database highlighted](images/singlestore_studio-database.png) +![Screenshot showing SingleStore Studio with arrow pointing to the new 'metrics' database](images/singlestore_studio-database.png) ### Create the "S2MonitorUser" user Next, you need to create a specific user that Grafana can use to connect to the '**metrics**' database. After logging into SingleStore with the admin user, you can submit the `CREATE USER` and `GRANT` commands via the SingleStore CLI (or, from the SQL Editor within SingleStore Studio) to create the user and grant the user the desired permissions. From 7507b8729d413a3a81d64c9a64ff6f0ed32cf194 Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:31:12 -0400 Subject: [PATCH 19/20] Remove obsolete image --- .../images/02_MG_202508_metrics-database.png | Bin 73873 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 samples/speedystore/images/02_MG_202508_metrics-database.png diff --git a/samples/speedystore/images/02_MG_202508_metrics-database.png b/samples/speedystore/images/02_MG_202508_metrics-database.png deleted file mode 100644 index 06bf140b3d9f8292c6f7911a3928a7592693bc48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73873 zcmZ^~b980jwlx}6?4)Abs$j=f#kP|QcWm3XZQDu3c2cozTlMlg_n!OC`|kJt*lV@6 zT3d7XImeuR^nn#7FDs4!ivtS+0)ikZA)*KZ0)7Mn0*V0*`Sk>%=8zf$1SZW~SXkcN z$Or_)HS;1(O+IlHC;0c@9G(f}U%{EdnPfk)1ngzw3rc$?Vg<46nTR83YyCqd6d_Q) zY1=x%)Q5*tL5c{1-ucskjkULimzG-PVS1ELl{qvySxV^=J9SrlVuCQaehmdeWtv3VZFfi`?zOjD zR$!m&kD>@epcE&_*>{lQdmEV-WZxME z->J>tO`%30Iz=F;ax3PY_cl0>XDfd2LOmdovEbzLP(UUSG$trZTM)Ht2!7~bnVw)X z2@nEf0fzHHFe-mV0LUMCsHhoupe;`OHlDVBg)Q1;4;7C;OlojSEy$HVwjeT?kmzwJ z8A(hjk!C1ppAa1i)BygCpnn__8LXtpT&%V+rea_s@gE7^xybjxOi>2nr8t9qP?oR> zVjmJh1^AzW*rjyk;ivg@3y@C2A2U&A=;@Ka3SN$N8&QD*a`{=u{tNwnb=d`Fasm{OtxWdzqe9oLtVmJqjN-g zgbeQuUR$`Lb^hSPB8-^s#oR;MS-Zi!>3^nvC-D=AB{M^zgU$}L6{5-Wl@|p_whCYo zOQUU~eG9!60naC84osDpAXP=y3hf#|*@d@DBa>DnPK)D_#8bp53tW&mCElQrNk|?g zF=ng(wi1IUwJBLm))H3}OPH_)4Gm2Nn+od+HvoN(T#61Lx0TUX+y)O4n=M>c5TZ6u z>`L5Aj7Wq^a<R%HmAw(m@ zE|d{iA4C&41-*fhj!6Mi0lNkh0%wC(jlxIE!_Y}3ggJ|OgD#0ojbV<`#=s&)I-_ik z$cjjx0WI@$x6*LUqscAT9hV<_JNw7YMj=C>WHR=hF_VutX4T+1+g5yl&-A246^)E z^+GXAB|+XnVO-Tx#iLSIrA1Lr)kgkziQkgG`G7gzTx&s?1&+Cx<)YcR60GtRw0*k`Ffn>n?IF z@<=*Srcc^JW=I1*8M7kQX%gMk!m@qiKJx_Xhf#xa!~8FwRLhLvw3gKAY9*~flmoBEZ+MTe<|RfoS(l9u3=L`(rpIgY%h_896JtWtiZd{aYP zs;d6@I!1ae7A>Zi>6biD1V{`0e~f+)?>*3*p)I+%`Ikf-c~4X7TIi1I{&wB#>gu%Y z%y~P0+kb_Bp7Y{(Ykuy&Yj~i&@z}4q%sJe`Btl2VnZc_?HzQQX0H74&HnJW6s#Ug? zwsnCfCL=1OHnt1s4+h6A7LF2v6B=eO2TrWJdL=9rKg%3(zyT4rJSpHYF|Zakbng4qGwSSuUjuMU6G~trA5SK1|GoxA(VWx0{!+>wgj$Gk%l$oN||3X~IFk zxqjR0m~>h4iuvF>e9Pmtd{Vx6Q5>P}R47zaR=6)q)$!be`XHq7QD4Drb15BY-M6Lg zX03Cy%K6icW>y#T;8J8w{H>Q}-YZGe*U>oUF z*(OS*_=xKLEqJ?Rz00HxEtbhW|nICwGER1vMlh_no^-TKS! zV%@3X%+#jV+Hr%mdxg`Cb=hwGSamq|M*awxu(shMeRU6CgL{czhtuY`^m+NmgW<_K zx|$H5;Eu3^pMZ#6lR>^dR5ghdY5`_FTeSD)+dd*R3a z_Kz*onBrw6Mjxq{i+RUShts=o?3c7djer#ghiC^ET`O1S50;aIThHDrlHW_+iarl_ zgo{4#3=s6vzYn`~UmBjH_A~Zu5Vjua-Rb$fQm(Dt%C5Wi-_Quv2_g9)y)!kYo<*LO zUo`d{rZHO>W7JSpRiAZzufF}Cmo^Z7%Qxo_Vm`E(are8!HBSMS)G1qsT~$lH*ITAjM%?mh(56R zs~KAeUs?^uRzkx81O##5pC4!vEg~)m2oZ>+h@i4-=6M&CC%Sku@5H6g)|%JW+BP)% z<7&s_FApGph|U^d2R_v}Uxr0jnuWqtS{5uY7MaKo0u?os3IY{7E}<{7UVe)6NHRU` z?!)?F!3;f401W==y2Gqk*vaYPB%9C4X5)0hG8jL8*AN*M2ewIbatPRir;o@4l?pxq zdI;j+%Q>@yCts%0THGFOnHP1@&IR3TKnxuvPt2+qH6x+It2E1^Xa`kP_oan#FtOKLGdOwc>t3Ru(GcV97W*rKsGoH_4Gd^Zxl#-i)tTVYvu7L7TE_Gu<>zb2fs>VW}|3T4Q}7Wvk@9rfMbI?B)u zsZCwDSv8uKm}_uxn*{hQQ7J(RZFA3j`|R@k%Rt-du)Eq?CIgoaf)+*7=C=}rOZJlG zR)qgqM%y<$XtfaHO38-MW%(qg3SS^u^I7sNpFO`pV-C~ny1abIO6mpQg&6`wCl804 z?3i2G+OYKl&axwqIyV*$aQI5cv*zwj*NZXCfjZcj5&yw6I53z90BG$Ff*>U$6T$LA zf<;7KG~;Hs4p`d;xfx$Inh?tJVS0uN;QTL>de`HbX{LT*$TPDJn&oS>F_Lo=R$v^o zS2`$NT{(rY*|?ENrB#6FE3hU_w2?^-Sy=`q|0xteLL+!6?mV?xhdhOw4?tu=6`Rq9=vBsdjXW4Dpp(+oMOZp#-F%A(ijCyg3aZ` z+G}nT3n!`tl14q|SGrToMP&&-QG`bQ=1m``)*@ayU_NZX&(v3n#o7(4Rb>+`Sse|R z490)q)yYf%fki?R7Ze07w=B<{T@#`8P-NV|D_@~H;S$fi3|%;3s1#{svL@SMH%Y&WyAwH2$WsYwW#I$tZ| zG#y7-MGdA`S4WAyQcPIYh;3D@+A?bP6S&gd#)5kt3e1&kd&09n|Tor@L~P$4ZTe{>c>qUe&y7WkOlGNp;d2(TYA+ED4Eesi>%`8 zNV0vry|ouj)Cxp~*~W=@QY`r+TrmqXzpxB#B7;Vf4dKFzvJuIKzBw6gSHuvNq5;u; zaqA%`F#K!ESD6X9whq8yOjKHyC)R6oUg+VYr*+ah%D+ z@!s!~*USo7HdornsIRfBfoJsAMrL?TTQM>oEHtS8`&d<+l zoi8*iwOSA>)M|#hz1{{q+{8s2enxrj^nJqv*a`sZfH9&!_+Or%L(S9INM>ws7G;Ct znEu|5GtQPNm54ny!u;uYfqqtkUH_!T zsrHE!XtV?!!$?(dldOQg$KW|uZXPv84eN>&D}YugHo0$M>x<+$Y~(k&Zhp9)H`SzA z8m&J8$T+h%&ZX0&j9JRGHC|O^?gbbxnuS6x)fY7bBLI}LXn#LGK5k~k3Bz=`+lgO# z$M~!NhgJUDm-#*J37DCcBKN>y(Dekupj}ULY(e9)S)dO^;f6394e1|EWy!cVtx07n zp+B!QnBH9Z{KaKpV33fIK)(9iA1!hBdOay=+2*tn%#;H4dc8NV!20_#?XxM7J8m+~ z`=nign=5H2E3{S`L{S9khDL+(=*%4bJ2j%h2sTeM1!@|}XlMD1W=@Aj0RT2bc9P4+ z#yBIn&Be*N^Mz#Kc(y=rx!sA@`Fxp}Pfb-7c1J}?$>_VqeOG(CW+mzJ+FHaNaj*3F zh?xg!pTprquVqbF@WFUW#0OP_i-txTfO0iBIZl$9DkZGeecY5QnWq{3NU212@T}%H zgS)R8?_`%u-XD8@jbyr%MHD=Ie7lo5@>wZiUI_>;$UhncM}lna6!i%E6Cm}%{mnXG z%iwc6N+}^L`$Zr81Mk8U|EUSKyZ3u0?c<&H>x6}b0rKW3i^oPrj%%OnxEMsoAR!>O_5QwMvfFIZMT_IaHTFE5Ev=n*{VoHPfD`b#qfhhP z!9yb81TyHf>yN||_a*S@_kb9HLm`Uf@OfSL!7;9XF=|23P_AH@CAp9;ZOq{z~#`5iGI;X{&GDT@m>6pcj!PUZ|oCwt9ks@{^Id|GodhJUPh&oY#O4!=kBI85X zYu|Q%K~qMSNfvb~Vli&3mxaS*2uw*yX_B_k(i*9JcG05RGEc}NASWj$X%7I<+np~n z(`h!AO4hhr4svcd4tVVTcu33w*a@x2YG`N};=xyuT3SwH|C>VoM{)IZjewqTQe4b4 zVPex4+$`d!5pjMwcf5!J&MuE}WEa$d!kk}|=|Ly+B`&3a6tJwRhmkna=l8p5X4h-| z`?Dn^wHn>;tGQLWZyDhZw}DC%d|`H{QLa~APa@MI{eDmT5vvhag25J)N&8Il`l(qlemt?DU7g-JWm#*3<5k$zX?> zmDbhK_?;&l0?WwbH}t~)cHV%+ZiV&!{$9E3u~e-Ca5#(v$dxa(YLuyels_n$_$&En-e2`MGBW>K5#!MNT#oe`w%zyJgK>b< zX(Cm~YEJcR$5l72s~8fTrmWbOM()-JA=QjSt^C$$=azsg-Au5-g4tOJU9ibOX=jy_tPE@E?p>9ztXAaOtffLzD`zJBb=xCoF z09-CJmye24bWu$vvU#;aTWh*sVbLgM(Yu()#)_7bBqR*>$%@TA!JEL{6sg;NQNd%? z3qrxU)L>O8cjY}$!>Hl2R`2#l6Y_bq{QfZ}Y_A+X$(GksRx9G>=4Sq$ufRk8p5iiJ zT#V3?IUyH8l9c2t6({JQFo^efaw#UCPtUrm0II1X6sq&g)ziHgevGB|B6f4h%y9zY za4XlnC=QXMg}1BUjC}l$%SO9c_qHSjh^XxZ1K`=eqV%AjgZ`~`{v`r>|`}hWJ4X?Yf9W_Zbm>QxB~9+MK$Jc5pOaR zQVRp(klo%cT7u3to$>snaa`7R*GolBejz;mWrKOlGR)hQhyHP2%CHpbHZ>Zc3rEl5 zb>DiQh+TJ;rjS$~GPU4%=!~k39xjW;?OZuRB?p$$cfVAl#|U|iCQ+JTOR~ct+$$NG zuw4{udMh;Vg4()(CN%oZIF&0&&ftTrcBxV$AUqtF_;b{VUQj4Y^U zY_A6N!xvw&)?7d=tf>A^jLLDVu@U(3(ZuKg6a2%=-FBrcaRyjg3!qPd=k6ABgi?? z6Ii4Fp=kdr!m}*_5S6SZ_jBNCYW=!t{|*NOgAy$tj#mt=x>oD#&Pb^vf)f)A>9X+b zQf4ZdnxGV&>3u&X_Zl&jYqQ>3H#twcrL?PEu_UCG=eKnQ)?SG-@gt^hgHkS=PKZOoR{@NjCINyeh;{zck&kRdk`9fSiZ#n!c704?tA8tn_CLb>Uz=6n4aP`LPVW91`p*nQ?_xU&YGP$z!8;K(vFH^q733TYktn{^fMNaq%n5YtlphK zL5f;>VSdgRv?_tjSlSXXv^x%5qnQG7PAZk%ATj*iX8C`U5C72aIyRz+s3;riZ+paB z?(a=MUj|1MXoQzfY8FO-yxtWhillP%L5@l_5Ndg%IV(_=d;k|AfL2s84<&KV!+^}*OHCyZhGEYzwe zjMzZ{B`>P?ES@ch)#%Q07SeXQadzB}`}Q&T>t^f)82e4Tmo|f6u39K7OyeEEHsxaY zc^ewIPHl?G$M=J}t7iFbEecU~7)J|_woE>yXU?c6n{qGp%)1!czpekr1eu@~TyhaK z(T|!*(uMNP@#x9rNb?we+{P(DGrE;fN47WdqRWIkNX>C{2|`6xL#Cvd7!Ehs*}iL_ z;&B!AUzoaGdo@ECNPUI3=DC)!MP1aSvnJd*t(k=D&e^s&l(MM^fBEx;3;LLI@Q<3IB$|BifWp^6c>9#ZRIIY|2L z9#+}DRGU-kHz+7L1z{tXyW87kBX1;V+2-aJK{2u5&{rY`m;H~v{|gjo_uSQ7rN1wT zr8M+nn(o1=YaIo2l$7Fukn@>q`^=^WBfHNfBcQw1Zf=~ncXy)q;{QK@D*pk5pwljy zwxm@e3RG?O=$%YDDR^ zw6Ks@Q1FY7N8LX>3_saWR8m^`kIdb_rQd{~M=*F=TAE=h)1<44ii(L7%O+4}uo&3F z?n*S+b{~)V{d*XM9{QGC&Vj2d;?Z_2#=pYv|9Sr(Z@aC#3*x3KnW|(Dw5L-1Bt<>R zoR;!fdLWOuTf0w2OQSBsM9J#aXTpMq4EVZv|17PpZsx-Fu>jNIk~-^qcp!mFcj{W9 zlcwtk2@zj1Yb>?yD=%*fND-z#r~_N2CRKEFf^KgW6VWmA8XK{alD_x((Mgx{p(1XVwOY#C&BUoDMe9^xMApF~!9|G?slT|@A||*H zb}D9aeq|Vy9xu~IJtJEO^3Ut7hIF0%*Q~x^6p+VS$K}7s7Sz_tM~d4pBDF8LUzEK# za#f|q0~k4=%0^*A!{CJ-1922kEXdYF#bkfsj5%p4UpxvP?!}PqE&UcN3IJy<{8mQr z6e~a(!wIjcJ+@>Zo=%`!=6)_c+y6rpYT6h-6YO^9G9$=;*W&mgJoXCNPPT8|d0p5e zhbl=jR)~w4Ss}6_7k(u_TSX-w5lEl%Skksg{etTU!Jj025J!}9Bs!d=)Ge9EFl_&C zlVHII)8oM2c973Vo_$45NPe>J5?m5%;;Coy>aijF1Az6=XaON@c+@>3J5mbN8;<-q zbRTf$uUigsOr~kJ;Lj3SiI0`(*q6T_KBbYN$eWHA^kzNLwdFX2Qr>_zNV&_hzQ68j zJ3cO|yFNTL*W+19&x5Bt@8<{O$MUVkVO8;i%4>Gk0(#GpUeV7=8&LQ=AKDvNutPBe>N1J>r3vfS8^EHUAnkt~Te ztiuWUZ^x5(s=qyc;D*xe=tuV{mE?Zb7`mTgQuLcX;~Whz#cQ1!xXH7|X(X#Xfrrt? z?AQj4=fW4j_9`5WF;*Od(yA)%;uW$}q9wMXpvGSiru4`Q#m}tZ)|7Nj;^5-Oi^%kDJ)8D~KBIAYtc;G@m-Y>Es(z=_ z%bMm!xrDWr@~AWZD^0qZomY%->zE^oe~tzg{-YpBB$)Pa-j1$Xr*R6`R-68n zACxHgxMAx9BKw~YH4+yKFy{P!Iavt3(39%we!9N#5>1U7Sua?|=_v#(Ie*{%jc0#z zT&&G=o*5C6Wq&=Atj)thhdS*|5LnU;FaD$fLq%2X=l57eA@0Z>=HQkWA0N+Tu|S2# z>%Kr^zcz2wZMP>Toz4pLm2^VO*LVbbd3iCo-5)*vQ-P_iqq9afRfMSu{(=h^l_wtWROo`2mt16Ex0!SwTtov7t%bes#w*2Nrs%)2fv?`T1 zHV2O%{}6;7zYwf#`r-LZo-n}qJQaB!{l&7QoBklKJKmj?j!rss-`5u;&m6k3y2!pP zKtK$?MYJR?A<+><6g45?_A7)&i&pgU@ljxK+b{CA=o*?2MGUB~S0p1}7qC)pMLsOw zK3hJnC7?~A?@d>st#uz{snqO7rv!^8V&lL~@^~aVI@uyUn-y0$IERlKb({`tjIe#w z#BUZy-}}u$wsSKH>18Q`~PxY}cfB ze04@Xazugd?d`>4HAAk}`_0h3_0!c&s?TRUnZD1+nl|5@H_k7*%j?bA@pNI7CR2-a z$^;dFdIUkj^GC~lFsxC;(A3n_)zvlhqOZT7*>nnTU|>MK|M=kXq3dXW<2$|Iyfq>q zMJR16ibH4lynU*>vsG}#wC&(U33(;n!<-0mF!?qzn9AZD{zBI zgCx2e->Rz2-V_8t3<6_PlS|DHeK!<2=rl`df;@|u@42RnGAgWT zio2uF8$6f%^G&n($*k2!=?urVq#9TzW5(%rf5JsG+(aP!&PKGqp!=*hi8gM5FxECl zBdkb-w+{a8iTY>1J8hW9u>GWju_h@%nu>8uSfeR#ldVci@9(g}dPQR`7v!eLGzrB% zy7LQO2#Y}Qvz9-2HZBTX`7hKX+Odiz>X|d)>6LZ`jyfJ15ZeZ(bjKKxNb`aU? zF?Tm6RMC8pF! zI>|A8_Aeq89jZ;qEPK=E!Ebg&(gEGgvki(11-j_beWq*9mdzJ!lz#uPWDE2Qw^&$l z3?3)RJ%l-;{qx0IiyWC*!$x)0LHsAtg)qSFmh7t)D&k=DpiphZLpHsrX*aXE37_$| z;UKKla;;$K`{&1-R?0YV_0abZ2_q$(U7bQ`I5gVMIo~FCo#BZgpi&F`jjdu(uOn%E zr*V^DryQBg#Ds{S6J=0Rvb4Oat0>TxKC43-#JghkPwu>dnJ?^gYu3OPPxRgu0jO*5 z9klK(XDH^|^x^yN$;hsctu30Q|ep2WF zE!0!dEP;pwRCfRF@ezYpiQD=7tN2pVS|(9T$m3cYms-<7T?qKI9okQlDXq8~7#Q+g zIPU+3A+9Z}0^v1hCk`Npws;(}I9Vi*lazPsFnl5};)v$@Hg&Zc9fG-5 zsH98YI-$8a7>0|a51^~^%p7)JTHs!^CHa~#WiO8gj>e$*=^U>`!?s25E=a#wFDTf! zUaE2FPbSM|t&exqn!ia(mFNeU@`o9}R*Vm9R^i%__oHr_rWMy8w{x6#$@b6jDz{`v zQd7}; znqL(7>_s`5uUdhEg+&#-8t)J<(C;8w5etVYgY!YKbg)Z zWa;(rM=c+|uTrC7romKhB8OkEl5|64*jna=MU#__d6Q)7PiRzh4|@u|P-FsAO7oO; zQmv&L11yq90F`oF>S6)(eoX4GJ9Kv>-`M<=s`?k&S@Z*Dd!SA*oMER!Hz6b|3I7;78zC~xrog|Ez z;9foQCYyU8f|`aE9V%xu2^>%HG1nuZHsMcnBCo)`QaIw|KdFb$=t44>&nK)i++&be z6S!p-kNlW6n`m+vB3B`6p281^+cP!TYBSp((hEv?62!Z=8#-@uzV1lR&(!)!)m)Vo zvBJ-_dmAOB{kR65BNZ+YM1iQK^F-1l|6)NU+fz-yMx<-WMs1t=2Z_-MHEk0e*SIxA%uHSBEC1@pkI(PQA(NyS?f!Gfy z$=dSOz&{V*SbXkaBtfL~_)|ZEjh3J7Qt3~Xd`C&4`Z?5BnqT`+Jz3o=T;rCEi-_qZ zzrC5m*#UG<$L48E_+ZXvJjXKRJPAo?k5waR{i!X;0L zKl%I)as#!<+-gR)`FvrE)GBWj?W+T-x9U@4NWUU&dK}PK-bd6rJIYHi5i{O{98TTT zy8gVYHJ`P}goO^cBfQz9^%?GI8Xnw-AtM;I6qn%b#<+64 z3Ks158OS6o(U;1#=fmVl-knd;9X$K!?qwdsjI)O>fck)nYhiZrHof_H2C*()k#(xm={m^$U?P%{OM#3*6>?OaB>0P&cyZ<4ymNhC9-;2A2uo!JDG>r2j+;W-K8!8?372Tl>S`j1zg&i5hl)b`|6)YjS^ z+|G|F?&C*q7ps^;TH~HeH}LDj3>(89SC>$3Y40Ge|L+ZrY#o zp+&(zC`^16KfDVIWTW~dUELNgib40i*$ck1T9-IdS}q9n*MG3eo>M$9%C zf(46;`VTjBF}d`R{-p#3r8LNC6}US6UJ`&c61vGS{syQACgJ(bsxRjq$F@~u-%EMm zovmgA1pibsr0V@b5Ft~Vr8IsA;# zTbgy!!;G}_qSDF$!-D=G0A<`|+lEYFqtx`vYm>8jhdcTCQni@GwF>ce0croh!P-53{ehdX z=f?pEk)yB{*Zmwx|MDXP?Q<7U%GYw+LOD7_Z*Oq%-{CgQja{N&y;eWSjnC$a;D%xd z8HI2m5%H+{)_}mTD!C!g^XJFUQhUo`(h;Lr3EfWDx@T!JGpc$?c{FMmqoGKYsGqGG zBVcS?aazu-tmsGRB!t-5)FX1^r6J+XCBV?cecqDT=;XmRjF6OR|9-wE*Iqs|4y5Xm zlOi4{2Hd3`Lx20qW#1_ED-RVEPTA#LThE8@2R(Bj z>ejv1^;^kR_r~G{pAER(^6!}U`m>j@B`-81_M!Q;Nq1u1;6M2A0`Kxy(NC)agHcgG zK8V3U?Gd*No`OmHaO`q|M|s72DU-)o^!v9jZ9A*A*H%XYu$bK8OXZjy-;^VrIHS*? zI1Jw>HbCl`clZNrseay6{DI)y4e*oQ{l-6I4g30t8=XemOuE9tDga~2K?5d07>L3v zMp~K+p;Zz!(8>Gr%J6oR`Is+zjG=cV9 zL*b{}h`!&CNPT{QAUlh+#ah9CJUZ!|XSSIDWd5uYz4wE0y_746{YgB)u(flLeI^1m zTsJz?8$US=SXwNGzta-S@W*Q~G8^BI*P^`Id zDw@mbEKLw@b1nzN4|KJK|7q08T)Gyrj4A$PK!EY+1>PWQ=2yz*dOJDs}$X9fLqqbzu7_4{?i7?j0WTzqC!{(zGDfhW#PiDAFC z=>V*~*-i_P+>?|>-f`&LoleqJvHt`eEYEOVRYaYdXnZRUD1&8fL?YWgpneizseUZZ z-W#|0qZO_wd23*7;mp?Q5o7aqjEUdM`Jw7A(-N+3-tD`81gO`Tf%MBSY{PQjQ)vDP z%{p98$vpKo3wlLMvuAN;cs7;R?KZ?UM&pQ#qredEsX+`9%3~r`8!oVXNm&cXaF&8P zuf3mCUJgxwgH9X|Mhq}f!BlP|#A=hp@EuYD+NE6{9WEn+$9AjWc66$?ZlpVJ$G(#@ z)15Xqw$5o|&{w?59BvpW;lv}!%qw@gHAiK<8j>4yRk|&IydTJQF1Xr{A>lvW8d%;>z4VgW z6rd|#j)Iava=CFX;6mrbP5-EL(GqZHckrzMz=1fcLD7>4we&~Ijv9)J?$-Efbdul~KFZ_xbr*)nn>_o$Odr zYIG+Wp??&HjO(i>#OM!u^TGJ^ern?Ai6(kRGL^|#o2X>#=nuKvy@bQOTL}k+5>WDe zXFI#zudWd-dW$lh@Cdjsx=z@A?`!*E7}>S~JLnQw0yP~)rvLP&(Jb0AqRY5 zU9Fe#^z0Vt+z-jiscw31-S(ndNU zCEFCXC^y!gx>JipL#uza2vD*QGhZxY$*!%FESaA+BD_PY9J3heaLOCcD}0-(n5h&B z9hW(l52P{jjr!(p_{6(TX4gcEutPTkUbBIVC=F=HVBCTuP&l7VoZ>= z_DlG^3!Lg|MvCr0w?PU!ZqVworJ+DtjXYCtap!C%;3;rrG4Cu~F2?cewgwPX#YT4% z+O0#Vw536!8ttg%^wW;l)BFMV@>Y+kucVTGe;4h18(jKQgH)YQtAtFBrtm_lh`k~l z<$B~8o|}YkXo)NcoG|LV?nIDJCw?h>S0N3YJ!~bj$2X#So_8OH1M?0-xWVS6-9tTj zUDuDaU3N(fIe-gg>5pC92tZ9xf9|ENGHn|~V|iC?l5AY6F%=bB16{>=;effx%7_=4S#8-Op(IZ_jWmLf`Qi_v}CvZKM54|WSNJ8(N6 z^*r+hT$NCMmHq13(Ub3uNK$v=f*E;Ok`zm-&ifs6nHVq4E|tq08j%A0#G97MA+Ljc z9|OQ!fwTy5L^|NW2I={U?T(-oBn>2gT%GKD{IJmGYsT8*mZy|PESAO!z7Xm!G`bzZ z2IQl%KuNjZhsaghUk1iL7~Nb9fs8v<_I|Pj)ZUvh*SjG0&NF)Z|Bb{CK;hNxZva0e z+23WB{yS|PxIbt#a3{A{P&2&K!7O||*1*_D3?NwQN;Z59*9lKyoP;BM(1Sl!qXJlm zpa?_mjZc4usSQ1cT6P>qfI^QnM@Dwrq28HJ2ufI>9wHEgN07HY?*y4%U*1^S;@jF2BLo@GeA8R9TWRV6eI{L@#=nQ6GmkZRpPvCRqLeA#Hpx4hr!3_=s zoM4@;H3O0|I%8D}Y)==W53VDaL5A?GviU*B7j1&p*fHtSSx`Fs=aDg8K|GMCvUmfZ z=LxQPqzrLJ;5gwiUG$3h?m=eIw`12dMU=r+IHC>TFnowz74Rbv5VIv{W=Y;#xsz+u zLmDhjH5dcd`oh#Zr&RD9ZYrs-AAf`KGjia;w7?4^za90A4-yFOcC+u!J<P2o?YuS=l;lYTz7`+i6tT;~2V~5o2!%n{}@}?+cI)OVkQ0QNXaacL6 zgnm<^*a;g^iF zK;w{apS};BMmH+oQ6g2uk7|CyF;tJ%Hef*i+(~NP1$;T&ZtaEv`Qp`b4E$`|ynVCl zzsikP#7@X3;5eT&!^sIySwlfeU~Kk}8>i|HG$B08&2H8ETr@d&5iD`e4zUXTRcRVh zu$tk~m$L;S07@`(hB@JdQ31E!_4RdY$;_1GWc9B)zT3d)5AV|f1*?@~h~bB`?S1_i zFAry87H#rH+U!SYk>C&#+8_Ass#C}mAyP_N=3ieESPRTTKR!P0YL{I)5+wH2Tx8$T z+@kDC574#dyzrm5UGqKW_`r2zZU)+HZ=s-a;jqPn~jKmBb;c3T{uti0l}6k8a;_VmNEW zeCJv4V$=qN2I8`8Ii-!r;C6O93Dj5;59&T~Yj*pojfgqeqJ-^%b??;rtW&kXGG31zDo(k{u+;euB*Zvmi5uaXnBP6j z?u+OH#4I$hb<~5t6c7a-G5w=>q_N(}yj!PHQmP1FpWt*!WYS)A`UoOL+ILd$zAm74-mGR|JwFI^zK!Kvn=Pg6I1;1d4tYhnK_xlgWUztsx9EseVU#kc6>4v0 zn?GOEiuRb04UkfB!OpI@3)J+DfTAI5D}p|0=ovg_(;8;JxOeoPl76YX%;x7HRvp!@$VcA4!6^Gmz2KOy8oHNr3jG*p3C!Jze%-ltaxN>N zB#sQIZRqxnC74hFc)@LA)&ptKL?e_#Ej7^E2#v&L1s&~(F}ybMb!Sz4t6~3q|0$f~ zlIPp978LFWYZH`Ha^H%+7j9KTTI~=8R3`DElhHj{1hGi45FS_2Wr|N zOe(WJbam2cZTAzmZM!BBD$JsM37UmMVzO^wr6N{&lE7Ifk*VjR2hM`v+U#3KlTd6h zFeg$DvPzITs-~J9yeQ@RfIDZ$%pH4fmjz@GA@XV->Wopcd6DF-5&!i*&ChZCYC@wU z4y&FVG;|}~Uxvxe6bpL=rrFyHV2uSvwhyA!5f_8Cy1>T-wUPUQnbA8^$}^wjuPcf}6eX>L(&>|HpRy8*C%_ zsI5)|WZnx!Dgw^&{TLe6#WAAQO^Gb+?96h#8FMwQ@E==X4nBrQNFL7)7`ycY$`b3@ zy7RWOqIJYEcuqOtp4mV#@D) zS}ognK{v{xecs)?)tD9_yiG-jlr1X;OJ%m&oOK8pi1G3q!UgjMswDw=Vmr>&7MQA4 znn zqemCvL6a%6QduWbGmBXK82#eMv-rF;CkmYoC$Iwp0~@I;yUM>xuYRO4ZRnf#ynGBe zY7AN8Jv+hxhf_d4$sfZ_2kbe9BmU{}Nk82!b`<&$aETlGwV%x)R?~~ka{mu?Z`l>s z^Rx?x2pZgi2X`khcyMvl6R+CJa&gh{F2fzIV(O3 z&L**sDx4D3iS#HXKnr0Nu)6b-Sq^)BIMF!C(Bh!evBUTJ*muiX)=Obxwooo6FMBb3N{d3laX#h6>*d+^gM#!yg{}k!9Mf8P z`1DDJ-9eo#msZABOVRs8bsaN0z0)wc*8{A?Vt;3_0H?)8o;Eo*b;IcGPVyDV4GP1E z@?*Cg?P6N-zc?jR`e^yD+H1|%SsX<^n&%7UtXd~{3VWHi|HhyCeFb#g<#QBDjvIUL z-4e~E2Nd3!3!=)=Wfowh-oIeEIeA2qoz{=f>=)~G&!57{Yi#(k|4;#vSI+-HHeXVW zvprL4b2t1@IW~U(^(cR9QbL@D?+iIdwmU&AnaJ$&LE~Z7KhTx0odeSFqlFo*9&$ev zSLLpKSoh33*X^ysrKJ6tZ`4ym{N;kY+KmucF&yurZN&1|_|A(n6G= zh+V;tx5YX>C%Fk+&P^1uw>~5;@%M!0kYuqZa>%@WK2Jsd42E#|`7n71TEGA9N18Yk z{jbfiD@q17{c!I5pf9*F_j-6SqbPZ!-?`W*3L#yQ2@y%3vKm}ON&>FmtjQF4Gn54I zV#7Y;vAoH+n=J(xIri0}bu#w|T zzmVW}4^Od2Hytl>B1^%nUt0@Y5T3v|wxToVm#e-X4s`|0|zWa+n`QmrhchAf3jVj;NC9uhL zQ$BOs!rsQ}*Szs1#aEs1A%3MxF%)OXdvSRYl_6%2Q?i;bC$UI_s;1YFlG_1W z)3~7qW~o`1J;%^buSy(#U-tHRroG+u=e}eW20CFRR1a^td@9g$`2w$ES4Vqe-P--q z%i?zIc4@l}Qw(XlOkOZ<&;c6igK<~aZzL@6aCS8?(dzCBsKc}VBvSKd`Bl4@^T5<| z!OxV8-E3}$OQM1OPt?MPfW-<^?DN3(+WwOwJ22Vs+V)v_s1&Ho%W@Z2#)pM+(LkCU zIQX-1>SALblTlbMN0(K6pw&F0b{Y1AW@?%5OA+60{)#jV;b zsZb!A-DEQ|S=h`L9NyV3y0sf@;xjsr2oHuk*$zI-_|gtM8&aY`FsCAQ=O{kr7koQ8 z9(29C3qL8*xd8kOO^Y~NK?c2w20za6`;&KM#J#+ga9r{;Y5*4Hll|p)>2;>!^m)`g zl*bKNyMIrkB76H{8|h51{qqN}Gx6BTaa*&?JoQ6fNrVgirs)jrOZu~svZtmb7`^Y# z;tcws1ur@B1j27tTPOexT;p<|dYPkCApvV;e<$pZiS=;SmzBy|vrD&**r&P|u(0Ac zE>_QD?X~#d^YbD_h>&mnZNxVeXx}l2rY!lX?$}g6tXmy;adRONpvv*5)Y~kzUO;3$ zw-&5jGzXM;q|OQ$H2L$!*RuB+WL6ojXZI!6y$Den@yHwD&i{d9n$37Z4 z7U3MwwW*Qc4inijRv30_hBhQS)tJU~ws+!|pby0@$y3kFYvK*o*Z?`4lmV)KYKs~S z_f4Kp8!Hu-q;{T-W##gc_E7J#$j7%IKIKPn)bKWZ3YVlJ4vmia%B0sukags)&TG&8 ztJ^UAc=or3;2IWTp}@yvofnly{0I!A!jqD8O?`boBDv~9s=JYfoU#nH6B8XnXToQd zchlmW{Zp}|$cCec56_GKEII^Nad;*Q|Q2jlZNOH+U7CT}f}Gdm9=A~{MzjZ&738Z6Y) zNcmbbqdve;ijkzLp&6a^9pGqu8hXJq{*Vln2RJXq0_e}yc?4Q0k1mOU7wYeKH0zSI zG+)FOPqh4q0r>H~U{p1JiHTh~r6lDQr75nZf~QK^{UsJp)Pt}Va7Oi|-nKt6B|jWp zrkI7ZGL6h69XAeP2tYOfISE>3jWk-!u5GE+j|se&DokTBVesu2Wq9nvc$v5k%#j4C zGJ+!`Yz^Vb#Ij*qk(+2m2Q0L{lc||4L1*vc$;FU$R5dz<)B*KNoWoS6!J?#~P>wlT zU5ZF4xoTQgag@x#KY+#&1y!k5I~3Yzx2*PI*nevQG=K0F5Rus1{|xNEuNtVJ`s>Qi zf{KI$(lB7A`qiW+ysxI9`BL*Y8}V|5l$S1P^k6wjVs>f-dfbR+#M+*A3h3p+BgqJp zHl^3l%FDILD2dP71P5_XFC40wv6pxL^5uvgUVP3}fa^*X@)qdi%ft9S3CJQq=?M@-b?nS{aYFxCW1ro)42|1^M{&~`(^L3ycMB6 zk`&<;I-yHhZPQDEpW2bCKML3e%Vx67=2G4Z8O2?ckulW|aFSszM8=@X=`tIuy{gl) z#4XXKWn)2GK<2$krDq~I`Q>WX`AT(&=#OZ^03-YN-NFLh-#FQyTPZ!TR?rEEb(k!c z$|NMrN!}u}Uun|fl9NVNh%9Fp%bCcM_i1}fNT=u+x^e8;(kc?hMix2Rm8%ERYZmH6 zDyqsT*c1M;dum=Go#kIth9Fb$SkMk$QRQ6#5ze)E^eI|0uHCvo7IY;pGM5^24PuKBLw1 z%#(c%o0B>T3U>Of>rx%XN%wi&#yok7xZSvV%?RPh@8wOyx@UO`dMA z7?kp9aqe^fPAse^XWo0hNkacp17Ibt3@r91$l6aq^0hGMKMQ#%*?bfT7HZfwe@|cO)a$Ux0OTM`=ZHQv0-joXTskG=sq?%Z z!;;@+EviZT_M|&jYC`wqkR7HTpPim}8O{I#YOtA5Iyjt!qE9|6t&*{8L1w&h$JR%(S1&5Rk5v)Q=PjRcS|wVqp;E}D**Dxu zg64db>Th}VjdM@>|F~xR4Oe$#Q^@@(MZ;xU8T3-Mv}FH`*-+U?U2)65qCCWI3e%c~ zSX@uh%4^oSMLo^mA%9k)_M2SvO{zpXmMz@pb^2`-aa943mM%f(Y@0Q!Y4X(i@qBWu z3^q)ckES$n`?SnqBgAO%WAsb@G{2*VSNJ%V_})qE?aIhX-q_x{=jmtX-@G;EB~k`Quh7vazL4~7Vmxx?yE6D&Edp~bhnl^r=x0~&4%)-GonVTaWaSHI+Q-g z`oKbW^&s`gW>08hKAE@CZ0oEbb3b|6^-zfjF!zu$B^N!-+QOd|$*GHVf1&;Skg{o8 zvJm!S9CoGW8RK+JBa}+u9Q}muyi!#!Skm}Z@^oJ<5`X#_8K|NH8nh8#73@EW*Y`$L zM;YEZT|HVm^*@0Z4%f);St9+jj-`fEob3IlZddx;*iViNje_^DSZ?`0tm?}4%K4>@ zfwejvEb4PL^Cs_+8*TpO^?j&Wcs&{S+(nTHGO}@OeuLSVYEV-Cl*s$N$zFw~CHyHq zh**Jj)HP5DRv8u~U`dJ@|K`E6a$T{a-q1c*a&mETxe|}kLjc4+;Tj%?0z`=%!(ZU`6UUd#YoV5PTuT*aT} zc7A#LxggA$H#Xs)O48VT8lk6qH7`{G=o+~^Se>S&i9xV_L8++uP_JpXadq5kubzcY zZ^B)5<9c6-h`Gs!da=R)3B;c5y0fG~pfALDW^BH3vDQ$wavEQ8v|Au3MAZVLRR$CF z`q(hX4yX0uw2-XSN!npHQZP;luaHI`+_eCB+=avZM{0MaJrsyC**;PxqzQ-)b%;8* zJmm?>lC4hfP`9s(MTb*D<0S&IJt6niJpa_NBji2v-maGJ8I3e>7d2NMUA1yMF?Y8&#ssyrb@0 zAGEE%`lMtDHY~6`*9UHB$P#DQ!Da#InYEqNNA#CuHbz#v{QraC{|D;zZ^+LXG79Op zP`1ftRZ4df=78qL#YyEwE$LSo_CD1-Z{yWh!|A;4a~AA=(2G{qHf9MqSPNq3AQG7F z*ZT+@lHkN>wyNcLHtFg=%Kr~=#+z*KBORtxyez4y>TFL+`bp{gF((yq}jQK3S(|De$63N8QN(h*{*?{WH$j<(A0}imhP@E>Nu{%6N23) zzMca9LM9zcHIpsZnE&LKu$r}BJGnML_WWP4FxP6gkMSs_z z3&AKrC?U~n0evgS=K2TufAsnvHkdDh>OoXZU!79Cw3crxcRJcikW+P1X_QQSed+(6 zQd};Vnr>lF!`@&&S7A^FMaHfEcow`E=~vql=nf(XhW4Av3@QA}QvRjf7E|i_IV~P> zMa7LGKy}40JhV4>_{lTP=jlEV1;dv!F2cK`jCq4v#&85oZ-$!O=cyb#Q+$1Xnb6(c zx0CZfb0mWEez@qS#BlJ@43X+A(;j$iu;;xLhhLL<1YTkL++~W_Gudiv6p)(%r~YSN zDWwx(4A^bTceaFJgIuibZCszD;!m^1)GaO}FwGuVj62xQsD{Cdg08 zY!9i4-$KIwg=^6DQu z^r=CdY1Os0txg0#4YaOjH9qWD2Ze~kwq1zKVe{w?!ELObOd=6-Z63YV!s4;;Q>ZYs zZT$RVBsure2t<5wHNSo#4cgolFs2+jFTdVq^a{E!yv%U_pUJpOf z+2{28v1uy1Rm+$soz56MZQ?-${?C61@dE^jfZ3z3ZSx;7@@ULq_;_HtF>#n2r%!;_ z3+g~E+=Y6AV{8`J$40!rPg-;~;z#l6LfsK2!KC31=fr&{&-gz33Gksp<2-_m)plbz z%EFTS|DMbl5PWzn^RrFA}skEg^>AQ*N1z(ZdC2=nBzGoTbYiUfCA=c^6s3|p( zKrQU2^ZX!6V<9+Yf(Z0AWzZp-2y979_p1WQ8I^y71Fio}6656_{&e*7o~?eKkt}4+ zn`PR|)POUA^*(8JM&#yd>E=EuB7Z=t`{Y{$)$z9~H8De%e27j?cC0M7Z2xE3nX#AcKyQ1 zie`aL%%>)EovhXAwVv$NKUcD0A1+>IpRl_G5VV=7u*24#MF)31keWP!9Ud5$W2&R4r^T*qp^s{uTdC=rJydzm zF*^MK5Kux-;+f>dQrc(O{{c zLnZ@tZkxMv3pZKNF=EuUjMocxIvR>31Dt<7u9B8ifk-GtfU4$)*q%Y;4&rN(KQ(Ly z?pTLlaEyrY;8KgR;Pc*1Avjrr=V>g5F#?cWnn!T=pp|<$Jw;Urru}^x!BK5-p8Y9l zlZpu@n?PM1+t;7l&PTGrA$?J(RuJ6X8yOp`NxEVs>*a;j(doTg9NZOOu4OA(I2$c^ ze06n|lyCZ8b4M#-p1AYLavxoI_ChM+E%CRk*GFxQSTjdA4_-HV)O{gUD1{vzF9!$d zN5(ln%DXZl0-3VS&g+-$n_}_lrhXLE)GPyo^jm|$(0rUNPUtRtYkQl1j6uD6v9^#g zRK0X}?c`CT#@tL2BP)BC=I$?UC$UL>p&0Sic1J<|-+>IgV}+3K>2j1aq}MSQ|< z&$^VhRJ(O_kfwfg=c_=U-4XqtlmT-PGSvWqMuE+{w~hQJ9`3o|Jdr!M^2VGMzs@8# z!?wqh=rUoOana)cEJpX-Y%fb#gpo8ZGjG$P5>$Nr$T;S;_i0LNN;azKVk=b1wx2&3 zrn6FlhpguWq^ybh3h^}PP4HB>#w_*uD}S*`2C3#|;1AcPSXVY#lXUWyY(`4DnH1|O zTk9vt!86~=qqlych1t5Y^AYYi>5>yyeaOTDBwbib=8x1XE627}YbGZnt)6HhA%jFnP^2IlcJFU}N)} zdx`rm=81OeJJ>9B-!lYhlapJLw>0y^JirE{7@VHiub&eMjSrgGFy(R`zV0VBVKiO~jcf1ADt zO-~$GBC1fGeM$Jx`VHUPpl7#hYw0ubIT*6{sj%6B`eg9oR{%W%Sjq~)t}tm#lfg)L zeSX69?HBeup8A3$)#7>5L@;HM*)mE^{Rs^_p~$zMzoOoN^Zc?0X>+XRCLo{4ymOMF z)$!)=l85ejagyutd8JYPY^^mp)!YQ!QEY4Mv)$iM8yORm{L?6Mr9UFUZq>(^HyB29 zcj}(L8S?ELv(}RXiL7bSg)rUJWSE33!LAq_98k`pq6RO0FJVp=3odr?hTx}Dn+mP z+bzMN_06b2orwTFOfu4<_jDJlqDHtvCw+qE?=tS{@-Lm0bgpv>a?}~gWEGuO@@wgC z2jP-U@v%O__|TL6**aBQq9@QZ)>hD29+WMIPfh2=2elb3^E(uQih%{K-{9=rj|V4M zg4^+@MBY`VXxl&5ZSIVC>|e~E3*__q+#`2EHnJQvNLJi{6>?uIvfAHzSFh@W`Kbi% z7Bv1-)mS2Nf@I3M` zS^2j}zQ1n9<_Xwy#6l693kor5Z(5q!Ri@y1bDzx+0aA)JL0DAqm*5wbD_$1M(T%}v z00B7Vw3dm-smK>9TMnyhSw`8n**%fw`1Xq}v`8=sHK%OG!B(6Zgk7Wr5k|PzJJ2wa zh1VXK_Uaj~6>l)EKeWh;MH8{y8kw86r~|JE*#@vpS6mB`)=p4^jQh$o>ze-h=dJs5 z^o@pnYBvO#Tv0wkAmfR*aL9Of5xC7cS5|)&y_a2bJxqX)ZV%lw?MabiJinW%$t&Is zj`SR173J=5g6XzAg1cK}3%xrPMlc>KR^P)nASqr>!oc&5z*d!WlV|2jUy`#mG)4{% zlkkrFBhiml!ftzI1m_0b*8zG4D?`Gi_I~|S!FWRH zZV=oH|Ex@->`&=K;Fl@7+EfR*&_9c+n@H@zO@B;*7x8SeyYBrBQy;J}4tOVbcQ)Wz ziUR6u)CC=~PHDpojmbHT`_EH^{jvP~T=fh+(ctV>*ZP+^7Wj~H#q31Zuj+T7 zhBi&Cr7zpP7dgbsvkh$V6P8`={lO>#crnc@7P{suujoiO<)B*!1S?d94V&Ff7m38u z{SB&UQgRa!aNd;4Pa1oM%nrze0k=D_Va>`Lmel+%n?2xf;z73ewL><<_q@G{1XHc` zU_mgMdyLJKwk?ZrlgI{C=fBXeypEmVRvMoR4m!=cI`8{H1em zVofSnUg%eXMT1n%m$tuE9tQ0obfJFcVAq_(6h4}>HQGTB^G^xqgR?=xQ-)qRP$!$;*w2!?t@cdEoCvHUySNbE=D9JxF*dCq zQmo1ru_rx$zPDUHe-1tm{JxOrdKJnDhk+spp8p=%eessbQF}h7{jAm?lM!Sin`K0C z(3*Dzheleb-yFWYpR1IhZM!Ft?T;or5^)kPlDXLZ!4RNV!!~JnZ*kUUS#;8uvCxQF z*@jsdJfD@~ARNa^lIY=yu>jLg@e}Q`wmVlPc&_21D0N8!-#6uaTyM*Lw^EH_t+-%* zi#uyUGCmgM$z)pkD%apo>GErTUlo%n@hg>Lc6&|flE}@6lSXGn{dG|x+$ru93?}y+o9N2O% zh0gm0sl@x7H~WAKJZ!mZmz`czo#i~9CtujdjXu=o`>jX3Va<_`ja!AAqb; z>sA;goEwj{cxQSl>ALq^i=gB>>RGkMpbTkuGy!VwJ2)Bdgm&E6Qi_%g0aeC*q!7^u zlLT2Rs<_o5Omd;XulNwJn(32YH|qK8oq5(+!vOEakbE%buB$q^_nK2i(?BKwC~?I& zywx`K-5A`c4s$@EsM$CgHiqZM=C($;Qdosj*v=EF@qDKO&Mb$0L1hnxwnfltF>v;J zL6E%KAtU`VI?L5$1`Sl0qxF~G0(b9R2OuL(kK~c z!N-#^75ckmBIkBW!qr zg%#B4UG%h-+uq{RrA12lhKgYUt-nSXyB2%VVm zqE3^M_mjUM#KX&rJs>8-SAqwH6oU-N{+vbuh)q1GC*0Ym90XFH2M2?a5jR|{MmmkB zRx*(xhXRO0CY;vnSV3{5g7LxdlUGOj#M_srt6pj2fq|S?oA3ZAR?IbaIq#?{exn~d z9pl+wtYa`lxYM{#23N{X{e{FQ$z`!Zj5p&8!?egZ)QbT(KwhsW`$s#z!^k#Z>W?jl z98Xi#^6pfN(E?P>pI%zCJMK1r+nAa$Rsf*^^bXrZELj$`tv<|=zhN87&PJit5iVP^ zA>(|{)8dDXJE)hVqeX{3K5+6}ad;ws@*?og;zhfS=RwGv6TtKA^@o^1<Vb_PD7)@Ql{>=L=l1_%M=~&8y5Lu~-5%4vm(4xyuubSWZ+V|&$1l3Nfj%mS7}OGYpm-QMA!Jem z)TsSUGAw#m{Q_C6c-zAB)i(PNsZ6nseE9P7RM-~+3w>psJC(4{Zz+T{u?84$LK*_~ ze{~T2u>l6{k1doAv{qIg$Pm6XCEwjmKsUE63~NkyCng)-h_TH+;2TGJyQl30f4-Lk z2m!{OY@l4(oZU<=cwjWQ(EI$LEJhH!Nkc3g2BwWBW*zK?J&N^*$A2I9K3$ZwBimgDU$xG+;3FO+EBHdS1r9>jOEet_x64s|}wReMuC-JSLKjA8(Y zD|f%2C<=Y}rE+ADtKU3Nb_AK$&T|j@m$CZ_R0QreY5i;cKCpQYS#NT?*rH}b7(z`q zQ4>Yb0t(3K&T+{r&5AZ>-Fdio9H{YShsvhmW*_plU zFVPxDt2SU8o%}8jJXSovv_!$M;ZY_R)UMaGEak3eO%||J zVJX#_Q?queraVESTd_16IDbVa?!D+J7AwYD@r>ud-i%-EFJ!7I8DC>QuJHJnHqBuZ zml-pzuwBXHHnxyiD1lbZSAobH{-%2#H9tL&{jyw7q|vA;<#+q8?{w9G68&IGzc1Qa zciNF_#C@m3u7K00yJz_AgBwkIcgN&35v-!ArS~V?`)ln%AU zV5v=ZjA1SOF9Uvw$R!W4TQ9X8rgQY24DvZ*lJO-&PShMl#Dwb04nAdp?7SNA-FX!11qqV`V z?-3v7IDy4XI4h6i=&yU?fJGPjSs|{Xs2!EzZR=;>bE-)}T(_@zrU4^g;?f%&lvQYi zj;Y&XJ?3rj?+I6-yC* zLkn+3AEsp2MuYwhjQi2pw$a-GkGBd)dhFgw+nZg&i@P3BQs#2|LzUdALe5j0!6DH# z6%g=wg1>}gNl|g`)!HJPIjC6Jif+BHcjfzYFWTD0TJKz3guMI$a5RutymCpx%IXDc znsW-}%`kO@UWXq_pIiViAM+07RZ&@7>p?{2yu{9Y+&iARNdFupV1c7SXLR8ws-!!v zMEYyun(=$2sPwz~pp#ifW0J=0rPe^$3yd^?>n0z+;anW8-ij{{yXZNxib$zkt$RI1 zx^y7-Gm#;i0Pt9rfH|QMVAY)&NNlNqF4T+M-cOe}G-#Q(79CH!ZO){cMkYuJMZK9_ z;;h|S+V{5-i8s5qQOZ%vkR2wbfwp0ba{@<>-JPe>_r}jEnnZsZ%UuPkw)wlN$htGS zFFEs`!Kyhbp1qcwh5`jh(%Dz@4PdrW*Hk6b#X;+fHz&L~m4;q!S9>H~`TP;RujJg% z^X&N`rhF}XfKR& zy|LK4QxoIJSpXZoMI|Qnqy0VIigP-d)s$9<@bkgK2rg{a8|d|psp9!l9GO5q5At;| zD=V4cjN!iGhdNmYV%lbmZKqD>KwUUWF#N^$?|f1Kzngbq=tPCCy`X&4YU!L(Iqs?f z@kh0zq1fCT+Cr4ulFv~*f1Cx93JZ2NNSEu)aPkSD(aut`v+eGdV(c0yhO?MVu(y>l z#CxV;tXyuVzBHYciZmjfdVn6)Sd*7a{#=oRWH=Frc zxUtf%8PsN!d0Z}OX@+P0QMs+6Y7x-Cwz3y98Q1i{$UT6 zX!vcKdO+)>5P4VZU&+FE24$~2(JeX}S+JAx63Hx)`gaJ0hSThBhGFeuXml1$E}dd& zb-8v|n~QrJv~;`^TbN9CHY|!39WW7s!%2Rcvt)N34c4g)%JsSKh}HHK-N|17lRsNR z;~j_nuD#aoDa`V{aY%so%bh@y-~4Ucf6azBFuaxXcIAA|mIn_er^o>(gO`O!17vYV zVs%u8{)|m66ul=6;(fu8hbm65?A)c}Ak{PfX*eI2*WJ>J@b1AGd*?}l)U^5e)|cye zTAw_?)PCgf+Pz@x?wOXnc>R$8*}QXo;I-;En*7joMpNOhlWCUH;}_~7cm8v`g5G_} z!rTmR;O|2zI1Fo75e|^;2Ta_3_qW3oj6NwirF#$E$98n& zI(oT@(UnrI9!DZRwQ!c6(|%T*d*D6Tn%u9eng{5grDY@$wjsqIo;E|=l*MNJP_dZ< z9%$8fB<3*6@ufPqEgmFHGk9GywnHioAIuk`^4>3`q0;){imPIlEwcRvop3vZhH3`Z zf9Y61Vg)hfS-ut*4H`68RUj5)DvNqD%~L}4z>PL(_j<*~UU_-l&eXZasOERI-V){3 zdFa9s+HzrsAQH+@A#-~CX{Fz)TtU2X9e>(h=MJX)_D%BQ@^WyW&h&?CCVzalGM4;I?1$O0d75J1Xa@PV(E*eRQjNDtQ z#YgaXf2tz>24BwxuR#fl@wRFcDys}#y=sPgH^MrHq4GGN0rNiyxfSjOn^rU946)q> zI4JXXOVQ%+o2tNGTg*A+MuH@+a#PWiK7F|=*-cx-lu8d_$q(xaAM@R^U$svGuMJ+T z=8`W3uH_GxC@G`2hsLbic;%sO&vtUf=evTeqfrq2oqdhpAL zH^n%FkZ7d!P_QBDwe6_`WvJ@g!@G{%7;B5%!)lIr#*$C?iul z^OY{O_}dt&+(y_D?r`Nit+YXjWT-SCZnV=WNv0H`$W_gjV+_HF?K|-g=}27$#f5# z!*Z`%pzfv`$+4bm$1#Z|IYtHli|6LurYvJq{6WbBel>PuVjh4~VfvXASw|?)*_P<~PD+jBk{oyCXsa7#3|?B*hoX&@>SxxYo$`&F*kR*tQ_S zXN6|eDoou+-S@`IoU86t{|=J>v(UG0U+xl64l;D4&~;o0<+l2>`pV@f0Y8wxO6qPB$@l2`rxrD)2B;MTAErhR(%>8|`x`shibT7Z60&HBqONHgysdJyyA zPzl{YEi{CLGSWAE=l&oE;M!Bo}NKbib99rD`WJbpeKc?_tF^n zji0jZSmWj0&&ev7_Wc+E)x0QLrGq`JsJZ|{<7nP4e+SXWF8yjgQAI` z-=C;%i$K9(o-0$bOenU%5Ntdt=$!rM)UYv=K@9;F@u*yZq+&+*S%8-L>Ho+@Q+*X5 zjSvWfvkhnc5rgvr~f#Lh{L~ly0=~q+@LH* za7w17Jx%c!&K)R^bL{_AD8f$DyQFrEikr77%WAy-eUL(Y6v2*z3G9juhV2GM6SCi~ z$Yd+}?ou)V|My&6u_)$rBmLB-r=R+-C7{b}$lkA-pTZF}?@aFN|Gi`X>&RAZnghR?Cud`0`{(+MN3b}&@_QRf^%^pQBNToC>W1Y) z5!Yp2Y}4-S;Q8J#Nzi*@=Q+Hpt-Tx&iPhr&>A2_Z^qzqsFXNpx>zJ z>rzv|MoF}D^SttrYTxsDc^m7L3Veu|N6ST275SH=+vK8cEji?*WmfF?eytWg7)#UE zN?!US$j_L&v;$=>{ZWCit=?B3-sc?OKR-dbej{xYaMDfTQ;tt7=CB6Eq@?gsimP%X z2Ks~;s41>R4$e zA-)mw|Jmu0?EU{Q1;X-~;@!U+ns8K#MSd%5$q`>Lf}kvSECrES@mL9v4hpL{5Bio! z)F=Ht(zlM*y%P!iSP31Ca%Qf@I~(OAoh5qXyq#E6qwWl1kzdk*rV#GdHpjl z{@UtyXyrY_a36mSC!Vg!UK(59kVW8uUA{2s9MStu@y1ny2TOcn23qS9I>xdO1gG~B zBH0JC&jf>culVP0N_}=kz;iPbf`wO1oELQ>V3$6K(&cB39iyn-X1$zj#j=L?C0Kd! z{$`qsbr@dPncc7osNxb z9s2j8#_yIZF-}+Sw&b!4ixkO5Kc-U~BsQWabB}BNq5#?PB_#Pw?6baODRYP0to zA8k04CeDd86a?hXP^Wcd{jx;X_EqK&xqbM}=bU-u6&6PKCHxWBI6*Xj&No6q3Tjyw zj#=ZBmtwrRtl1zjUM)yY00cFp{ieipGsxpiFz1!Pty?P~oT+|dKl7k9xXls&p7tcL ze7?i^r!v7T^@^v}eanH08zO5w-Em388y;^JHE-Rjx0m_;wwFYfpJM7PG2*Jd1;pc0 zccr&CoE*t{X?zf|EcFx{SySq$Qsn4Ko>?k;x)#p5dL;UUqAHVB^?^Au6F;K%Nx1@= zm1JJmJi!RD>2CTvYp1`O`BOn!R8i*jzGhA~Xb^=9s2=QhOV(Etv~It0?l0mJNs6(y z)ERoV9)bJb#6HuHhlfW#c{y`nk-k5(6OuLBCEYowoj(;h=w{@t>u)qIv@pA0m{I4) zSoa$5_J<>Xac4w>cRI-=@&~o9*0sd__;N?}4)PR0@SB&{=|`S18{WD(*({Vrkh$Yd z_=Qfj%-ZA((P`#dyjNlK=(KESYh9AgHEa-=7l5QWepMd-A1eqObyUL$Q(bliFLe4E#%7BuBdrN7ENJuD0sR8xuG z2P*O`8jowVUMoA7yz|NVp%ZHr5+`DZvmX7)vK1nVxERQowb^U(RC+gR^#f8h$WdPR zb8!v#vYOEgDFfZ&AQuP9Lrp-}6^g8~o=j-Pk{H@2g1d~u3>+;P;j=#H5*1_R7NfH9 z>%JqMXm<^vQ{&)P}W(oL}hm|tF=>&$1K2B-$z z8Hz`^3{UT4xjGH2#hR9+DiC{5mG*Ca2xW{q8TBGx)_ZU`8R7f9qkl01`g%f@R+H7WPTRFc` z2Az91m$$;8E-TEv+jdNn@g=lV58&|vKYi8RFo&N#+6hB$c6XK8QK&$tO=okj*$82% z%Ly*d1vlcqYL-o}RZ(d~L9-RII-mKDra#+Kd5BnD|6zVh3LyVo@2!B39tAvrTT4F z>rk1`hk`^2`*8Ab z->{Xou~WC{arx~JkL*^v1=GoPE21;deU-&T8E$|;Z7u}-1eXPK z=kig|S3~eU_YY?omc^5)94F$)uAPwjRg$APkg0fYAF~t*-vcAo!$vw-_|zsOHH5W( zIKg)A+dAFh#1nheLdeOS)sRNA28Jb%PEA}nd2QC%59-ZYv)1;M$SC4w9*0w+fm8+) z(E-iu{(&Lc9ji{H(ht8gxqSGhOa$arFf4VmWm8}!VueIYK%LK8vxzEsbf0!aXd}%h ze_d?^kMZ=*${7;ZrZ-t*Twltu*WR_Uo{4d!@gB~e3je)B8CQYc0ct!R(HUYhBiCn@ zay)A-9==dJ0(^CZouM*BFhH1jh+N%eLu3!P>%btM0}7)}Y<|MRPlX8+@VAOty3Jm% zMeV!S_PFAH=hi7@3u&hX2UH$uSaB>oHo+nTe%#(qcF33+leJvtU+-%T#d0?~hiZD) zKRLqyOEGT>Be-|k?Ui%5lALJug1`cgz>1aM~(AMmTI*awJM-l?g}eFwr0r}E*v=tN8`>4CaMbc4}p zJJ&nbOpm_$iUgcewHBsV`bnHjMlGQPCvK2$gY{8QAkOGbziD46uuXtu09stn^jw{g zvFC+fo%(zvc#AWTZ}aysA5}Tl%3xkL*7I!ynQq5@HxJazKSxLOS913d&K;%DNDoV+ zzS{$3giS-i_Dr!6_VvN)Ss?(ATFnMsNxLIA&waja_+D?elZFb+I#Ig6T65sTH(+FD zwtjVE+z^p*^LA>P)2gpdi_WN_P@?}VCt6{sDp={bAy>)nd)^ji;OM3u-A{B+f3Q`T zeSM-s!I?JmN_Z!@y593y6M@E|To*xe zq5N+uzDS$Uf~1!oYNq6KoeW3YWd>BF;%^<5xyAHdcGF;e!gl* zAmGGKQ$Okx3Cxo|jUpXLFqd6EJtNY{2)-+^=r{3sZDOvt;PMW|p)|nSs$(6M-`SG}iekT#&&nyWf3_V7P`)r1kCH>er)KfCmx-zm|FU4c+tIqi?3cs-F}cPwmqX2>|X%H$R=RO3ro;*&8294zXAl5p?A z&_`<16F-LY%Rl1$as3Re_GvIIh}6^0^hAnc?J7Ta)J$A4o@ETC{$&4zlp>Z&wIQPTSvWG7OO3tm*>(x*}@7`5>D zSr2*k!}EbohPo|yIGTt_ldY7(ikXhM4G_is4twI7tSj;6J5gQ^yauL_HEdR5o%vdu z+xcB#nN!xtUZgTwa@Fh0JN(-Euar_XScb72 z<{-uyg%$>VuwXKRFYf4Pa&%DjD1roG8xV){gtk$64&jIw05QItg~IJCYH0GHbC&DwIL zwRkQ_>iemU%NF#S?9c_9LD{x;#l4|sJ@EkDH$TxUcPJ>W{}r97ykwu&VX*(G zC#_Ko)+VHYVsy<;lA%m4zf^u`3Wa$7HqO4m@LH@HtF`^Pex)sXs!3Vbpd%9Hr+#tG zH&DwbX~BLA_-*4~tQu02Zce|JvxO~|fSJrQ^V0&$@bW!Oq*~`nnvZ%N&do`4p=5(n zqxC|R67l2wPXkiE#uLRSt}ct^Vp?0hyZE;u_d5N`<>nK`i30J0PK)4U z^|9!SXoV@v#CL668Xa3x(~{w9z0TZUKcaw_*9UHsNq)tVE#8f8UCb%zJho37!raGx zOW8j zSUhaiM);XLl5p=)nQzlK-1;%oF#H(i1{8I5I&eJel1_b8$kw4GF2(FH$06J8?4ByA6nd$ zsg2r5fNj?G`+KHH0_JOR8>K70+4|;x^px7XURK(y*{4oghSl}&sI8Bi@kY(EX{Mzs zFVnDF&aJW^o!%irKdbctDgJ@oW^Kirq$Or-PPY1_=EN zfyS>eaqbnq3c{OWlGHWkqlMVmEmC%3qY9q;cyRw=Nu$X^@JBPfRt`CZ5;2Zqmr26BR_40W{!`jI_0ZcBm?d zzzs#0UQ@5(r|(-S&ujgG!|aj+<0j_r783-hq&RLh(k*n%!5^QTpYM5%lM)@W=7Lw* zQNnRBXt*i{D|g}l{Q0z@hqOBy^1K3i_eE=AX|m zDRQn>V>)(?&+Oto0;-oLSVzy8GyFh}He4j+BS~jN(A?{iH%=)I9WGJGn1t%~vl3p5 zRs-cG?hPrjmfFabBD?q<4gGrn&T6rq5Ze8g(ps5VrX%SPoS>DijaZObd;Q4Ur-3XD zv(eNr2XLrYRePOH3UW0hpNuYEbcvqT>r^N(h{fq(&$Azc6V=~v8j==(0qLQ{LBxFq zzJCx-+CGL3!Jl8FsvGSq;O#Dq!vAnpwNJeDq)o2Di`s7*F;;vnV5KgUVWB5{cUdmu ze^Kj(N|0h78^lY+Fr8LyhA?ZBh>I$KtJ3a)Nu*2y5L*jv%ymSmt|}A(^8sZ-qOLMk zn|B3t;w)z3= z%t|EOLAPkbCV5LK$o3PT+WNYWi42IytbSkqKx7>KZJ~?9HS~3`9^S-4&6{KHP@BJz z%S`%riu7~cSEl1w9111E4H4Xfq1FSlhx$H==CgH$5*GT)fm<}OJLWvi6szaf=>Wr` zliJ@Fc!R`6nh*5R`iGP2XV`RLOOh5!=J|tN1Z_mP-!C5)eb1eNq+z5dIQyfXwCUxp^l=Td1oT;4OKW@Yy@aXlX**}%#{P`S z!zW6fF9cB>a5}L}->J2G@IFpCAJi@otb!ONPXh?i72jmx0P0n@64g>9#S^`McHJvso+{h={#n%P(;9#F zLBVppvyzc+Y)0%&zGZURVo;YfDtqID7LpU0Ab!CZQckgtWqW?k0=P#saLxOs&oitR-IT{TbZj z)z_WYs!aEvx=XNF439-f88cBYb4DKYoCX{@(n^@s$lP?el3uw7jWrgm3cHIWxRqSQ z2cQ@=*OL0kc{>s@;I*kYX6m}X_@ zSJ8Qs<7|so7~P6j{n*y9IS#wlm9xG;aT?x+KBzh2YQyiA5e%mVwrqI6yzp-Q&mAoz zGv<6hxNC!?VoEwfQI_^{$B@ys#ewe^!8_a#U7#HH0LQ(XKV9ykz^v1w z*gJB8Y0Ck;5ktXoz7s_ceWcyhl!-wqD#r^T?xwV$L#Y=CQi;TIzN)YVPtg^yG`zEvf;LdRdL^v zT0W1b2kN`I#}a}M>I2iejds`_zGAI@M{KIH@b^H0K%?L?)Ka3X6NC<~>Y=&a_X#aE zj>j%Pe&Zw&5C{K^^_+PV#mTS!a_9pn zIm{b9*>wAfA1kgm^BJ2op|=b`B5#x1?RhURlTCoqMrM<^UxaD4l5h z34ZJXxZxeFXZ&%p@w3ty@2Kqsp4mENPY6yEe70*IjRE1UWn5T{jN@^B=HcGSUCE*` zRr|!_37oi-U@qA`X-isSsB&EG3Y#r8?Pnq0jqkBolpQ%Q<$qP>lZoqJ7`P^xh~Akc z!DX!C+QnubC#MWBl)mUJR}3q@alhMN8$PYQ^iDn{HX|5iVUPHcWT#!-WPTFy5AQGN z@-WZ`rD4+wnb7@-B9qJo)vj)19=7Gfrap4i-od_aW7#?Z?%Wg03q}`%rt#1a)$GQ8 zUJ`W$BQbC7R+`0>YgUP1Id3jxy^;C!o%CJn_BX&pG4ctxb1TeZfh_mvPMpW_k_|Pn zfVXQQr>SDuaW4|2NIhsxN-NgbUb!sG-AoGFG&(@PCWZ0XZuBE2%)WJ?)o~UQ?DS38 za6746KNR^E_znq`XWM*$k6Zb@cs0h&mt?aouABW@kWO{)ka zCbSXZv#}-R!v09m;Yo=VBJ!GV%1gj)^E5bNi?P7M5C4-{{MXt|vFCzPGSgLzY+jFF z-?Mqt6(q0AzFz2nfOCG2pAhuQvC848e4aYx;a7JJ&s$ns!M&izGVQOZw0`O|dPD0S zJ~NXYa(HwUm&3R`=nc{e0@GYMHQgd(LwbA*Z9G$-I=v4_z$H7Fqn@MwkQL+ZOMuPQ zqT^oY{`jzA8RVJ!<5~?sjy)zWam^i^R3Id1n>!YR-|CG%1y@O}bi8NO`BbkQVU~G& zkv95HDF$3Jhe4{wV<8xaV%t7nrs(h2e7DFomMNx|;O+S8ZC*_7KK>y!$OSLy~>O$!y7p}|Hq_(mXUA8f?}ptrX1XoE zX+qk->aX;{4=j@H79Y{Xx-Pk!6xHjx{N|nyqOK;5x_(8&29=>r4CZl<@`{IWi+2~Y zvCk1IIL{C?xn6$Od9rvq8T2!b)%|+e$-kqo@fk_C`}juLMrtM0uw?l+)k3&oOkvzakY=RCy!1h``TI(I`G;e7EN)%jpXt(8g*{w>*EAt7Y8 zC6&xnTrZtWYp%zBYR#N9Igy(z3BEL3$+8(7dp(=*BQG`?+s$|!%i410t2<9ZWb1hv zWUI1Su+i^e0YeV}ro3Fd&1(4V<%(g&Yl_TQO;L_ zi&^90Hf|>Ln5G*8jWMNh77$P453oU+%>u5AmF|f`3~#1j6Tayrh#u`-%EL3E^9I0R zm;F@tg5tAdjsY10xqdCrSNf%d_h5nAwG$b!!sT+Xw$cnu^^q$ggj)~Da7ph!>0CW3 z|Lh0_5Lo_P3P2(|`$;c=ZyD*?=qw%g-t+1Ag?%y?RsxV3>^ZXdC6&DKVXX)Z2srpB zUUZezO(>1MXWVkmpesk|vRoGJ3o_bYQeu+>im~irLBSGU(Fo_E4*F^AnzR-}Aj2#4 ziy548=3*K4xV%?Da2s@}Qu^f3OJnzodg) z4lYCu?cgn%t*9p<@ZL4F{!KHy1CP}(*r&(tUDaUQj-ptEv!oLA9R2SeS!)mH|1&^R z2^x~5kJNrEId<7-vq^28*|^L!oSQaC=DOo$)Do_l<2;o0m(2LT(27I|G=w!1nXobS zrDH2t<#y{br^N!4u_M`&?7M5!60iCFG?M$>-q?AOBvWo{4lupEk@B zQSGKTO1ZV&ihlRYujkFvzWi$$?bArqi9ha@L=32U6#4HB{-5`Z4avlN1`Z>y%~vbd z;9^WtAQ^r-Sf|>4=dT*TJWbnwF7IP_n~h|z^>4-hHoK(Ve>X(30Nr%avVgxT)V+5V zGE|Q?UZv|&B-#a9tjU5tPH19Qd;a7(o1c459mo6ykp9~L{@=#?-#;Ts{|LtAuwCB{ z8Em`$#(mPi!n&~10U?7!C7M#@^Et%ROwFn`XXlZyOlette84vOf+NEQ60eP)_c_VzTODS#E5^KF*h3pM*uCe8e4Q+X*b|m7sBsGPZw08eU zNK$I1lAKd!yJX~+r>gZE1||sr-Zf;WMJC$6(k_0-9X(J#nE^b3AF`t}I6NpDlK~m@ zyeYpqTB%m97F>Zc7s(`dbp<8kPgDY(ut5iPm~WEu9c_{dKA>*vstbI4zP7ly8Oh@% zOKR~&BaX%{zpm8c*;|Zr{mo=LgMeAW?RA8Xi7CAV`ZDi73WR94j;D{rf#P;_da7KP z9nDTRtF~g*!O&05iIm>(NbP+wS?I?v1;6**ZADfh+m*|!Z@sz5#xcJ$@K&#dN;Le|1kbW{csn3c0tKcW0YvCqq+jlsozy zpTm!~200wg)hwQpYHuS8i;MFX%;FOgs-fgrkL8D>Bg?-w?Tx}FSCw9Jl+64WPxjZK z-|iLkTFHuL&(nfvtF*kl8DXfT2TYEJ+b33P>)oSyHa%F7eumeD-;&8JdP$BZC1XOh z8|_HRTX&~|gDLUWJ_g;*!1q&-&fInB#>i(?$4#iC%}T@mUI`f?t!t+3iwwFg83me# z+MNjaNBujq596@O$e#&SxbkfNb76zu2MVysDk@HS?{r%2dlmPs7($P=2UcMqoy@fs zeNM5YSIJu~ZD+<8{VD5h#G-2RCZNjZ@4K+xJ0wGv-%nY_oDFM~oFh9;e4#*r{|iiz z+%d`jsNmlkXXzYY%VF{k3k({hc7?yFJ=Qz{Az0gH{`kJrO(%zv1CLb?l`^sjxL(|y z5IJB)+7B=I|LbS=`@G|61tAnjorW7YEQ-J=(XGK41qB5$KxUTS`eNZARWuE24iHH3 zgxXp8ZhJDQpVN9iAU`+73+j&eYhXy=|1vN@cn+4Wp4!a&nB+MWIb0`qQWhM^92b7Y z>nRT8wp`3{v-Rp~e7Egpvn75`vSr)>*73^~cBkv|_LKkN9}g_CJB)W!$l*yE4ewwv z6X9XHDTF#uuvi|8p!8MmK;itFJL)|9ysV;f5}hK_;Liz<)8#^FxA?FBVU&{V8;&+C zF>GVuLRO+^#LaS!u)PXflw*M^&%2Oaj9-RdI8;&qL2i{w*$nso#&P_G;CdZdx%bJGV{?Qw z9y$RT8xuspTas1oBeyE0xcJ|b>_H{fYDG`da6rthzjjCJi&BBN0<=BnE^8x^`-!hGrZ$zfbq&tsLPFa`NS^>G*7kFq>_f?rbqxo>j`JQ*6ffx1`z6Z$Y6bOs+?nIy zu;;BIzr4dW6Oz=2j9~@p*%at#5&N%hTeAoooF?#KM_@^JR5((Ugpr~o2W)2M6dn0+ zu7P16sbihYbYP~3^AGsamKaE5x92 z8PmE|(>?=@Oc)v&alW0@aXSUaRdr$NwVdzWUtq5HxEmeJ)fh%+z>abVU?WfoAqLR& zhg{EiTLk}@;252yNEn1nDhRf_)EOdjV{9SAF7ORxUDQ@w4{EBpT0T2CeQ+fn`7-L8 zprF{IPlPm&nigRAn?d+wRK@dhc&$*A z#57Wjq<|IkqD0Gp)X=-TGl5P#j8#1u`M`-Bv!L%;X_QKRHU8d0gX_Be>R3_6i#URt zEgW^y10&PsGJoP6_S84YgFU-(3jSo*{>*RiaU?C#?dkDA)T-W?E}XSf>qxkiE*ra-8| zkYdZXUpu(UG{qnTPeUBtKeXyV)zL7TV2Pkx!!akrtar7GJxcD%-C1(;+dbun{+mLB z3d2T=tsHaW)!Cn}!n&Z}vJdZ@9_amv$MFxe zTo)6rgvVt}WV`DA({kc=(Ru|qJf%BvzTtfXS-ny5+!~rt!s4TN9&vX4hn?v>k!F<& zisdR##bZ~@3bx#Tzjr-@56H*QeNv(~L#5I6Qi?viqfvG@e5mCSR$>@L?b3Ioyk6l%Z5& zRt|H{-II-8b52y;ukEpz=*-4UJ-$%|WokvYJ{d|T!6(moS$V}21NP(}{=T;qm#Plu z&xU?L)+9?z|NgUYWX5I8;;w0`DMvPD@>1=U&`iJl)0Jb+58odd{j?jiye*9_3A&$% z)43eElKk}ttFPuR1(R}4GqmX9Ha>LaTsOKTQZ8_^KpH+O4`ZHt>G}|iv0ADn3%<4D z7nVeY<{>fvt}}UTJ%6yfMObIqNV-kUWH#ip1g^D5lAH8EN*)l?g}&413D{HIdim|v z%hg^@BG_#%D;1e}G zC)70%g=26M&8gfKio@(+p-s0(T=96~Ce~zsU#o5qNQ99-U}?s7EB5!wxXvjZpF2U* zo7W}LHwNEL@OVkfTxx@6o&%-;gLyd_g=OQvt$lO0(vuTnZGxh@1{*IHR@`|dyOs6L z6;1nYRd!ws@NT+3I2wae38gbQJYil@2i2>)q70vIDy|8}(~#75=FR-C00>tA8&YrP zphl{xg4a&lkF04Ze_no1jZ&O+qb|_S>^~FNDXpxV+%l$51)lmj@v!c`TqzK8MPvtL zP8HL6`#>jhbj5_sMCO6zH(_tcJ44C28%G~uL}D?olCr!NMB{fMxT0vHSfY_Gg_vHb z!6aT<MpBW1T59%aq5ocC6|Y1mN($<9%;!yUwY8w6s8 zqt~-u(G+xC8((~9ZL@ftxGXw+3utD^+k2iGKW7-!{;2UZGTLUQ!Gz_1nyGjno2%sT zN6{7PIKDOA>lE!Wk8FA#(apv?t;@n@F{^Jwt7I`Xw#Akwf2- zHUxNb^KG`?3~c5T1_Z1h>QQA%5*}X|`NXJFK3@>KL6__BjMwl7y6s{UGOYx$TRYmf zHSNQ#bU&@&%rd@rwtoK6he`3}$OM0j=F^+YSKJ-c(D|+_m>pLdg?Zx7%KWw`zlv_l zyDO1aD|~QNS7GKkGkl(ITE+b zI#Zdh*7)qBVG%v{YH@uF~q<;0D?8<;)D!`q>6;H<3D6a zdY(!Mdj@lN*BIwlaBY*@Qpq*-`1#%{MI}-Rts3$^hi^4F>?H2ImYJ&=pKHed<5eJKOZb% z+3723>Wfa5_x{TQERmY!8xpxc_`Lt#vXFd5>Jkh3_TGd5(YH&-kD^b^kWGhuJZtN& zB56j<9fgHtWbf-c9D_O5tq%SM_lP={NPv;ya>6Tb>U;U=3D53o31wW-rPpPPQ%xs3 z>P_osF14!T<;DAap(@?ya*fKAJV^YNG}0$p#sgPEj>0QAOzlTG1U<$=pDD!h$|kf+ zeq(b*@+2|PGA>(P7uxehE>?HlQFL|%6BJ9ztzL3m|%x)ZBRC>HC)2aF*O;_rXqt+N}sga#l8Xt z&$+UYlcd?aN05u+ucskik^77QH+u zBR_5@<@ivyLKC!yIZk>HvELom=cj`!pvzrU+RJq(*yyeB^fh?l_SmgdVk*UJ*7=yn zvg1fTe3L={Q?+7d!6FaE@Q0u_-H{%1G>JgSgFW9{xRT>n92sO(=4O zOjOX?S}|kv+U9JX%k7WeU_NQw*DsvT?k;q7z+!#|+=9L(fht6H#{p|{Jp=Yf)V8fY zi$59|kKO-sa9p7QSMS%?H(2OkRS!8-j#kmOA+dlhi;4cn+?sPE| zpf?cSb?Xkhe$6 zXgv?zQ`BmklCWh8<8VL(bUJ3XGyXN$g%|!^Gnd@vt2nuX!?Y<)BunZ{T) zGTeY1QVt zr!epC>^0d5Rp9tTxC2M~) zW&>o^aH}_Ol0!yP6$_oYjZ*KcOu(0484bGwb^}<)J5&j>uHUSlaAlyA)Q|Hny;FZG zNcq0Lgb8+`o`!{;6Emoh+vX2DI=U*a=uTyIlRtpB1=jE6d0T?3^P6$@knhW!%)UNCsx4z zF*=<%Y@Wvds1SK zn2QHTUBppj_qav7vgfzLuW-#{xZJz!PVfmhJ-31lzIb&S***#Hx-QRJfTXU}uh&wY zzArM3*DqRH3VqhAem7S+*w=*hiFi>Y88>XCjsZB?XLS^}h+?@UKgqW%Kgm_-{yJX} zpMXXYF9?KAZ%&FL(h+Ta65(5%)Tt1p^>>NH`i7f=3D`_XjcHjxpBs4i+!Qar-%9EUQhCy}udT zs$P_x_@z^Un?Sw0B4EPtftJN=X+9(xuj5BA6(u?x?jP4CQhc_lxG8JRt0()cR;=vu zJtjYub}70UM`CSI96;ho24zt|*Nek3R+SoZG?$ueh3aIFgWj0J%m5tP9bt7$CA~UO z06gyqkFn)>xP4-&IZc9_>zt8DtuY)RjVgwQSNJG}j7GCPC}QQ?aygtxAuI<5qaU3$ z_Mq}hAIix%)F(bYe?M82>{XvL!^a3p=kj4>ht!x1FOE&>`-^2P&Y4DppwOT&5hq?JIX^)5vkEz%Y{)jd(A=~d3UvRa<9Gr{&4r% z+qaFVw!M%ZnnMbe^*{amb?&a?X`m}wa)_oR)cpak=w~IGRLo?#+|4fBVli+h%rP(m zK$4Y}MTlrY36*eYUa8f{$Ka47aSBS;MsFJrk)-5LinlH+WME-uf`b?sPan%r^L40} z&w6cc=trhTk@MYKxjWe4!Hnh2NB@}cR^R!ZCet^T2nZW4dHeEb@CezK% zBsr0|r`|MJ%pv7Q0-UuePWIHsxUJFtdF)KBL|QMURa!b7qR_w zJrZMXi;SEi{X+*z?fDOXCsQ0&}=0-?T`>-Yy27+nzq6(-|KHQGNA%;h%P= zctl7@oQoeVE0A7kfP4{k>{qa(p!kgD|8@oB@rr(dL#cD0v9zN#|Hgq&YTH$p45>zO zffc+MX)-ObNcpsey38Q|>g=f09Deq?oWyJFQ}E|%<#X&gcz%hN6KLA}$D%rTmp6Up%nSF%-T6z4>OZ=I=`g_FxppKVRC0j7TgXJ*gT zHAUw;m<4&{uA%LXjurPa*fQh&Tv0`C8;&E{2zbcvIZ7fPm-MbDRL6_rKO`yb`Thv) zy1&LADzLY_^21LxcbEdleRW>+y36N8&@bAQPCGtKEj?d$0AIwce3$yz&LWQ&@zKnpBNg;M52^Gqci3 zC9Tv!cl2uD%ID9)Oq5-AqerGG| z(;E~jka?bS+R*@tz5~ z={_iIVUL36;SHa9avQ6`aT&ub47hB zKWTo~ka0h2ZjK~7pzwyKf`Bh9GB4+yBNf$(?yoh)xBe`Df41u0Qm>sBdf=LUi1-7` z!ijlssEsk#PwgaPp&UMuX?lw34#VE{^dbAj%I_wu67W{c+e8QgXoti^F0G%#?7m2> z8585CUdjiN`!EGFhpowP_d;+2UvtBBW{@LqI;H1|R$9To&MuFg#iyHetK{rHwl#m; zn&^6YjXnA<>KTj(&3mO5(VE^j=^1e3A{RTt@6-}iaa--{ZWyh0nFh1rz>PSaG1#^{ z{^~Gi$rps_ZeiSZlUR@}jz-mDUQDBoee-b~UB7bPjKE@Ya$*a}LT`obX~3Bb|d0 zTK1M%;$*#TyW4PW5gK<_cwLqi9gTq%O#6^1t2iR#+uXR!j*Ga z%Ml$J@C)5l@(H&+ze8HfbeKFxGYi+k$r24^I_?h3yPDAExFO6Ak^N0y(AaJ>~di53p+sTdsLt;&|cVGP|PzpYtizu_@IwJouJ_5+gpzejR3uh{!X@2Yw(jMYN|?pPscx*i zvH1mHpllDW!Q^QoN-;!5bFe0AKVb3?jeRLzaM=i^DBf*tdtSt);R&5-wb~m9d*1q8Dar3Vm&>!&9rR@ov^MCkX zZ6iW*`~#|lL8YgL`X;621Q(ptqx0hY6)q9DmG$)emDB6V2*&n_d(3kK7TNOV;YUw% z<{N1x@%v0!|TrR=& zkG;#;Or}6oPf%xdLm-vs1_(y>vc0OvZ?6kQ!2a=qQO>Z%S#%!NSE!=reb>P=b48WB zClDx5dU+7$qjyd_H1twd!;5Qo%Gs&?VB9P=OWJs#k9K}jBQj6N+22V1K|%LRVa3*r zYoqqe+xhms$_iC<^CDj-9wM%RK&^0o>4zJqUhOt;^H$iCS$Uyx3?_wnz2~@|r4zE_a_*Dku>n zrRhMY-Ue$S9qnYB0RFwgy2+GUwU;Df>^J%08&U{m%{xy%6f(hLYUaO%T%v+>*x#f!SENa_z2U4jgP!8NKRJ zn(tAqg4__i_G-7h*m#QMIEzk8mN)Kh1#ywM$hu2pmFmvyqV|VUpwd7n(AICozSNG= z{MIMFOp$-u*n1|1s-=uhgW^+CnEuuuFft#&$i~i|%j=1ABT#cv`L`)t`_RGud%lEw z08g%)T^%gdWzVfm7;)kH%g)WS@LxiKA7oo@!?b5%bSfWJk&l;c6B|&VXoG)hp`L6{ z?L2qoav-YEQ!s4ohK~BE+~m2tEiUggcS8_%-pT*QBJaB z!&J*&r&E!;jGO{F6KBw3vde$Era&l4VNr2X&g<{7hEj;7rKgcSj3l(TAVvx_yhvMR zCYPwdK{pegn;;lT2?Jqkub0YWX{+wzAa*Pis<8+0@cjFe9sN`-2F>jTtERHI7`c4H zMf+P}y@jE+d?IU4&hAqAqUEixpzaQy6qDzP5^yEj#Zy6Z4JOV7t_Fr*&1dT=QZyu` z*2btynjWkl9Z}(wc|t~hiR*T!{Z-;(|9{EP6R8wT+k0k_EePK``>8!|RHYI!Q}L3< z*VLoMcoe9u7jatikaZ8_RKw*llD*5@~!Lq823W9<0Ml@;8PLp($kpw{ZGyuTJQstnSzL8%D z9FH`7&ackp6sUMi*diNypiGpy&_Z(|$DZivTeJ6_1mr%awHv*CBR`I#xjE+g`3P|J zIM23{`^BqTO}5`wLmA#cc335^py`xY@$sdvZ0S|0a?nSQ{7~CQsXJ;G>J5h`Pye@k zOauzU2Vi~NnCnw?^u#SYpx5vS;%4ZnK|3oa^)HJ*uj#fCiDBv9PAWILc?T7|AIZZy@qfBWG#{ zot2=uE-Aje=GhKxz}cX^~JhJ4Ek@zATxr4iTPadvcA!dwtbRttdWrs_#~BdA@t%g%k|%F5K#gnJDrQJ>YSK10-7R` z*3#N^zh`M0Z~U2~s70`Pt@;X;?bj1>C@pC1kJ=r)cwmAGGfGaAN({e6=4C~jEBFr# zL`$&`_wXP3hv;-EpWr5qF><|}e2F^25+R`{;cZb$pUjUrk6nCl|F~hpM*m1B0eo{; z$*(S_-E?RAZ#&=_sCfMkWV~R85YB!bM^|MraoL%DKGoEH&>No81Xm|sKI136Y*9co z)l#ynL`xQ+8M0)QCu)Cth+*8_m&oopYmZ%L99A@fg>phq!c^?1{>ik*AA-J3@kPxg zsZ+>FKUXBA;FSD#l2L+E$1(L5TAr4r>iulp)i^G6i|7F?#KrX*j)0An| zrrz{g6TAjuAz0Vm@TH1Z-j#8GMiu`v_j%f2iT+7K$6c=dZM`E$T_DJ#dVRS?Ak72x zY!lOR+}nw$SN3OZW|F5PCqCJte_==4{glj}$wIv6#d*nu)TO&r>1A zZv>f1@)zC*LFdY2V`W%e6e3!+51H}mm1{on5~{Idr9>6lznq&2bhMX|VWXv@nhgGJ zu>4+;#48^Wxgr64-j+nBDoyzFMTf@>7!yG#+TF&TbZ-rb=G@4$-M}y|-)c@zpx=yx4mK z(TOx!8NaBBIWE*Fe|^39BhC6a*v@vw#Q^7=>8v*}YAxklih&R}iFl`mnWX1P2g(E9{r1#s;PYx}(CLLtPDiH$PEAiA1Tp!~?=K5Q-)5vccP{yn z5GRUBM7}dngC&1A2IR$v+UnO9qd;3kMruCgZw1DR)IkiiV%<{LF?=FJf}!Jm){ns_ zqPcxLeSo8-Z9e}qWoo^eT`v`S{PBn-JT0--xTzBv?bb`FuZ=OZm}%-A4Y5XM z0HuW&B#7-gX=AU*bCm`}Lq!fDT#5L={#b0)N~6?p943DyftmG?gx{+eBeBR4g(r(_ z*Wjby2IxcW*mdi2T4%a#2TeaDxR@g-sl+FmFdZu&DN}zr+_YU^WDpr*kB#rMu7}T- zx!O+W?mdshY(@*$sXbJ3?W3UReaqv?8o`YUAp`^_LTt zUfWpSvDz~XtUJ+U0v>V3TuU3aPt41jd%fqAYJS7eyE;Y^u8iHee01Yh7Xx4wIpZPy zay4wN<&rtd)0Rk;Y?q0X4zhR#rw~Xdz3Fd_mr2sN?_%D#;QHo94i6)hea{BG1IZmVu^8q#Ac8oF8 z=U*8I!h#*>zhsRrutp!d1SslZ{vmXWo$DDXpni9LER8RGh2w80OHR#@F*X&)>M+TK zQq`?=9{X-G+c~QWk%c`^?@PawzZ=*Lhe`3^FqBY%#5-$Gfyr;+%@^!_@(VkwbR%B0+RU+mg@?zP5QGk%QJ*r+&(@up`aq@-sJ215v@>G zOSvx>?nu)Qu$m|LB@^vCq?igWQWR0|-9E2{5*vo^PD*{G4vsIM+Dn3-@5x6^@hUIj zQ}P$bnGYXijk|SehAAbnnh9qvAc< z#QMt_q&QILQ=%C;bZ>mA$iJ)NxI|W)CT4g_Lq)Pi zLC5?5kF9TvujJddZAP7RY}@7zJGO1xcG9tJJL$M%+uE`1?AXTJ=l;*R@7?#_S|935 z{c2U!nrqgoImaBss6vP?b;@YHlDw?SD1UmyXWu=T=C>llBB#H8yhM+^hstdQctCg;AgPL1zAv(mz56wln>s#2H3)UJzZCHPI4(B2-&n1`np!8NQ`y=u zblxhm8AnK>6J2O|5`n{)BAn{`#jrKoP*RRWvhCYnMlmg>H2ccQI_9-+pfopE&LI%P zm6nJA`0jS~V86E0Az)aKyDm6V13nCdU0)5WkaM!~E4Zp_|H4&IT8;!QVUNBWNpsF8 zJCl;IKK}%$@?tJ=&WEIF3ObPaM24q>)AQ3AL83&^OWa>CKtoAy#bel@1xv({!oOBq z-=ax>1I&H|kl`c1O^oXVsCn{tlz7(-GMe|1M%!YDUO;0*g+(9sCO>AM6aTuc223xHT~b&uJX z`?)Wz>AV@sSHwdK)lTi}d;ed9*KZJT_(2b$(|}f{zaLO4XB}4RQ4~Xvlf?gaK*+5P z*vc#Q9{V0;-dY*LKaxvVX_E)xPMWTjqiiv!CRc0MCF;*(9ld`s2tIEpXeaF^V9wrf ztIpIdvF{U&xj;K)PcT(8Tear4S|+3e_wYXBw4;o+SE+I!TAqn2rmmmi_(DWXLXV#! zbayi7N6P3aOn#CPGIg-F#ORuA9(Yd6yFEu5PO>5<%&mrRLLiiRPV*jG{b7#&rDN&WzpsYzkZF0eLk9v~!v4 z=&mm+9rY;?06JS?dq!`vgALDM(K%QamUNUa{+t$A=OB+_c_8}N!uU(v7325?Qn!u0 zv^0@oJDmf?$~W<}$Ri&=NqvtmO=|`l6$os=cHxw&&)MJM$mj5Hza8PuGNrrDkoJ{64kY)hK9(y_-xPa97O$3}znj92N znI0ao|My-s?8{g1{v6 z@ql7MCd)q!}tBO(y*s}H4-=Nv}$ANOe51r%tP&|G<{I|Gv8E%eWI-}m^9T@+b zcbgAZD$(vhR6@_|6J-2GmJb|CYw2K4C1kcqaN`aBTuJA!lb&qZ)(3E6PLtj!No$uN zJw;rto@&r#Ad64qq4}*y2vM6*-!EjEPaY@Emu*;nd9XmfHTz7{Rv;Cd$-minc-e(A z)}D>N?H|=56&u?c})&18rrvNg3y`8h8y*`0hunYqa(;X8A<8Q z&(%a`Hs$=Cf)cRVFsgCY9USNTgX3bb%@7Rys|KX6C=xt$Cy5{T$J@XOhnyW?b-G#p z-p^QSD7!$}YG5*17#FF5{p)pN{Smk(W7U{F_lLqDenz=G)5&R^I5aGc3vhN3|5~_) z^rWGB4s%LLn1_Lemrq@*8`s>V>z-OQ?6cnj_V!P|6Tyn!4%r#GLqbE0Mwe#1nZ9@_YPTv_zQp|=xFq@lEklT{m z8Ow4&PL@|aQ>yMP{Uwzl%w3+gAIGHv!kIk3LJ=V=0veh8e=&OMj~h)MLsgZe6KW0} zplQt8o$sMtK^BiPy@Fda;lx`;Thc3_t8qZD=ed@B6j2q#+HQ&0#dI zbMzdJwawa;*a9UlI>qi_1Q+d1-W-ahG6w?1yK1(L+<@<~vu#W6LiU#3IPP%`C$jOv zY$a@GJ0=jR1$4FcldQsgKdaXJg^dk{q%M2bt@z4|Uw?2nhh6b1rg1ovjk!YRHwjIr z#QwXvy%UbKkPJ<-0LalnqobpPn;%5rHEM8EjJwu~>XDN1k{}??>Y}Pr=gT*e)O?_w zHg_)VXz~`H*1v+Cq>VxMn_`h_fFfmgva+1Mf!1-9;}7*m<)+*{RJH zn_k|IQrcGREAzWKWI`+gXYWCsjizPdBaBmS^aFAMH+vj$_(!u00w5f?4To zOu1@A%Y|Qew}$3)#jczpUQ0$CQqLz9b52E^@?v2_*Sa;#pzn$_6i zm`%}V7HebqpUv`j#E&lk`j|FPVQwC(t>jgzW0lXcG2viVY2V`E{N}^8oo$`Zu8Ukl z&27r<9~e#7fXVZNGTx?;RbAb&bp^hb>V&p;82?xLy-b{IONFoo0k=Y2g`J+i@mHQr zBS)+M83$<+`d`D;aTUR!9}cKm{dJ{{$#7H;N?lE^-5>a%j+VxJF!j%+7MkA3R@I>y zl%z-79r#fE=u}uj^CWlf$|&a|jYu9}uEx1hfDTV_=$WtlVpFwmSKqW>^g%5GjSat_ z3AvD_`5i}M^?Ed7AjweIqlQB`f@^C}fpGF>Gzc~c#NpQ$6b6%%9mjLWv z4mV8nX(Ke&Hn;uw(dg{yK2~FF@7m_-30Pa7pFH+XYEz8PxU1X8kzDQ-@ZP*z8{OI4 z>e0MlHx8Y26NyUiZoWdsqFcQ6W5 zwh1k&bnhTC!l1)wWhhC;6pxKngy|8Uve=_J1YY9Jh;IJog0{-HMU?lxCS9Q~MGyK1eD?ws?G{+k__ zhO{QC?>{pJ#N5a~GtJ zW;!&3Lazd&Io4?~Ah~^X>Q~YR$wn$6S6dHPB&3Z(DKawS(%i-;fZgiO&6ek4PbZ0q zO`eIPJo)KL+wIHJYKwvGNqAjC$-e@)|GUY?WTq6g*Wm_H&u>4Bc|dWAv?;hOB~^!7 z*AU%iHOf=EN|k7|zq=E!G+BuR1oK^5E@nHKEvGhVYf*rdqGeCmN;G41ZXX+Poy&bg z4bx_n+#Vb?8ZSg9vw6(l47GJ`oO*%NX|>h9GB@{KGYyvPE9}-nNu$+@cOi{V=1*U< ztAHF`R{&a0mpt*i7|IVB>y-veVX$zo`Dz0@F7{$?-=LrDNmH(7Q?}E^Od2P?%HZ@g z;$-dqU+OcdiQt>*&qD{w1xl3Ir&c(RxdTE%5QTdQT~`)0Wi$X2|8Z-UrybJpB&WfJ z8^ggfMA1U#c6sT}vI5?RdqQ2kl2}LCqRxI+9LXiQ$|tpN`!QTi{<6BR#gQF6(K7fm z`O@G>{(-poi)!hOH?_~%N>Wu8m;6H=RU+kC_bNV1o?x5FT-9QvjCR{}i?U*wic8PJ zNPx(M#%u*YaXO2+^rFqW`PI5=Ge`4B!JZa^9sj7Mk8()R4>ZL*EmEA*bqd`oq#_B< z%PY~G8nSoE5W4w2@ZuLrfdgIiq;S-%cq@}0sD>~ z3OJOdy+&3B&L4wba=t8i9#bTu@kIgM(t`GXv;y|u?e&I9XqeEL(<(q8JXMXlwL69J zO6i40ao;#U>sANfw(9-9{h{PUCtUhmfCx(aYI?uhXL5rGDxIxknm(RcI#^F8!xcf+ z{~g(Ex5G412zgNe!mi#u-HGmq`oW4#E2n^+^7zyKURfE4-e?0D!||>W+bK zyBg+(XA_ma{`TocgJ_sKK?Nv2Q}REdI`EO3*5TYpbesK{>7y9BS9Yp1m8WrEcc5`; z>^7@Lhtkz3gWils6k*Isgr%Cl^r6dG6ha99x*#m&`1yRX8dG<^OvXLqn&qTPd)WnO zOGZ2xX}ar-{H?lR!uI$+NjqI(qZ9|<_mUUy!b^zngC>+)Mz};Fv5X5P4z%Jc;JWeT z1LNNdL5I~Zx-Ti$+X=l|eZoMdWw1eETTG)-uJ(6QraT~_fajjA%60f@=Xhy_Q=!wJ zt4OD;cNnlZkO*e3ZZKHL(O@_)7M9-T)kSng7u~3sOMxOdSc1i3U-#expgZsHh{eIo zUjmXouVBMg9*JRYSJ5BO6nsI&8Ix=Ez?LxBPY30h2oV| zuexzF9LW?Cgo{+LuuQ+^7`d$?6bcszdVhb~#A}~-D;B6{cQOlh%o9lb!yfpfR8K61 zkc2yU=?_$IACVe+9$6JIdTGBlGe_eUP-J~dd7=<3FtDkAnv6madd|9G2;|iVY>rIo zb_zge)N&-#1)EM>6@FDssn3@u<}2cDf`1Q0B9+)a+6n{}7@r3wy@^@S1Lb*Iy zHFquU2N$gNJ0zc!{`8Nu_6wEJ(an1WGTi8o>5Sf>h+Vylz=(24I+>q|l!h@85nOc9 z(Mu~UyQj~OmO$Z8y!=ztsvaQ`=wA~}dF-}w1?qz`+6XS02r~bZh65k_XNeANvJDs@pUOqqa<4Nk6dzUxS*mU@=ZCE1&mFZta_p#ghf`QP z_Znm^XCCx8Ng(CMWRz74tVo?VnspA4}(+xVGY5hXg=bSGm&L?UuM79C)> zKl#w6zs_ZA;CF^)l&@-A0%PbOkwisJNiW>a@NUGv65UG;-tEh(xvW89a+&MYk+}Ta zzpS`sy_pOr-T^7U{OGJG@c4R)rJQoTPo=Ow(ey{@ignbZ%o50Fa~@z9FAH;90QB6q zcXlp$g@nUcn~bRLycnN`6QJGxFeSdqEQvfGl*rv2SVxwBk5 zhCOTD-pAkU%>Q=^mH8y(g>UcP$SjIvt6I!EM?ZJdz81pUV>3y7!VEZ}o%9b}=D!pD zZp}YQNG08=oMVZ6Lu5g&sqyg=7RPm@JK4s3NzZ)qep|fISK=Qi0M*LFY@o|hr+ke1 z%YcT3m`o(OU}}z{;MLhZT#znJ?-Xq>R<=}(ZMoc06ekV(x7$;d^q<}wrSGvhLF^W}ju>`|^(@=FL{>-|U3jArn93kn4 z)_^fBf!_-t>!Qwab!+G;Xr`6<>EbnSPqm$NE}cS^ z>?o)}(j;J$5KE_0iQVF(2glcb);kttS$F2&+?d^bsTn9TP=G$4f;s9{jkeUG6nv46 zqg-Xll*)i9Y>v=rh&dm=w58DVb#(^SoY{<$u~+*Ooc;8bnK0%u`;q#CWaq_6Nk!76 zlnmkQw`UYzP9^Uc{B-cttNN$~q3c!vlYhx0dOlvQrz|1BlDrQdqW-wDN$8Q#K2JN5 zyx6p*NPq~iY-LshP-N-w`A7{Z=T|yKJ~u)%l4d2f-^vP1;o`1QsQ2m+E)mVIe#A@A za&c*<0cJo>{{x}(@7Y7az@4&am@M3L?f_-mBd(ECQ=j0EI%X$aw717Uk2mfNy)Kn8 zueW+m-!0mBsqPw*!ll+FVCT$P^FPR(J^ghMmT*_elR3$*x7EUbP~|%q(rw+{pHHEy z)Vww)bv+$h+ExKEYc!sSS7&>JHu6|=I@B?_utm8yO2x~6@_?q-BN``scHlhGGsl#{ z0w{F1N7Et6o4&FM3%KSAyFW&ipVFh(JulBf@OP-zD%Z#KZFl+SS0+F!mGB)NZqwIo zoQcRn)5?WZH@OZ;9`!E`klL-c`Jyo!P8TZ?jeP9I@paUV_f^dt9TV(PE3-wGvaQY+ z(lO^9pcRnnvG@JwMp7I*Cpy`rCal>~O?Xb{Q-P9bZO}|5d1YtiSow}uT>09>*Npfo zFQprD&i9ps^ZZUB%pBi9M@mSmtc^mMT^A?Nxo}L?`k#j}2L&MG-X zu2uHOgAh6=n>!xmQO>Ig*>%ub8C`Yjs(jVxVg1R@fa`qM*1Cl>=-Sef*JC~@=KY0v zowI(oLju+PrAr#LQHqPNTo#y6aEQE5(S+m#{}3+gENW;%At(sB};CBq0e) zQX8YtX@$oZX`^0~_E#n1R-@1bbQr30XYx>J7orGDa_sCJB|FN*~rv&>eg44U$wG9h9!&jbOq#J4?EWK%uJ?13EiERa{CTl&)G)8n~m`Yf)mWY6)Y~ z;U!Y(7bL%hFP&E8YXlS#;*MkBWVYV(|W0_?&|z4!r49jQzh{;J?9m?*Jk& zaP$0J9#J-8Psf+WKQzqRAF36~;aCSz_5o%T(0iTk7#&2>y1#LrZQ1sBPNSNTrg7AH z>=5Tfzh*DIE8nVNysfhJ+{U$vJle4>ghu0GA7@vG@bLK|+qWe18n7Sg+2#B3X0z+M zKBR4|c1&J^SBd;1`EaCEu|~J!BlFpbvV1P2;l1)O)C1kQ#7pH^o|cO~42-n7CMD4Q z^8X;SsKncd2fI*r`3MKe6V@K6R%LQxMp{tR!63OY8Ht}v{}+%;0TM5xkTSoE_*u)K zSryiuzBcOaY0ZHSY=|U>wFU9?hW{t}YpdG1TMzNXHERyDl-bqkSIKMvs^ysT@gdjh ztr_crb?}Ego?-7VB!_J2ru#1xG00HT+I2pYY-5~v{#w4^ZGjgdUnP1iluvx+JVpMr z`83Fw02zQ0-^KUODBRk(a$+jQc-FyqSt_I;ksBT(Z3(~1uhf|6%lS$>WclvpLhDv& zfT~DWTyo(LsYUQjeo(Z~M0jJORtbiju5PIp!mA2?L~BlH-Pt}_2-4MLt$hn)5T6z zw&h`TLuH#kF*u?w_0Oa*1zu{$f)f=wna1 z+xVK01;`8a@n{vzD zMWe{(+r+w!W(ua?lLpp*FIx?gj4A<{4Oxz+_XApEuPML)cdeKw{%zPbzc>65&EBXHh;|$!argRJr)V#Rb1Ke3J%CIwgibR=hWHto2cp12 zSQch3)=U0I?fguj3AW`{I`#tx-Hegay3^9(7=S=dW}-{_ei z!PIf2y}orfP1Rsh|B7d~4pny05!CPlZ2QI%(!rGLb78z+O|QIO405ux}ca z`6J@6#SuM~ahE+97E`!HM&}m9oEU~&QfK>-=UbeBK+ls9ecONf!o{2A1_FtN50h|` zVHe1^qVEsMs2};MH8@hQCU(A>*ElI+}6f9LKk6C!=>@D`x#)$yX zi^^S0z`&KZNWN?yW))-1m@4W=K+Os7q4>IuqUAl4#~dn-#nVKuyK}l6u@*ThM`jIc zGF3=!2O0;^Y5gRe_-4X5LJaNUhZdK>3HT*CXq^;!s5a!BToWu$zd>b04w@>on9gvD z0ZST@O_h+@KdqSqwK}E4e@clYF8wyySA1QP@Tz-r9RZ;Cuiq4=iW5gRk-||hg zjOiPNZO2Us76hlp>H%}Qy461-zJ-wMGlVflqjg|llLpz7KC*!{>X=%H2LYVYWYdI; zEf{u)ACB+eg2^a{HV9u8Ze!%Zu97d3f-_}c6B+WP6VulljbRCT4{ zSmvYi?av#?wBBkp;~sZ)y2hP4oy|Jp;Yj@UVm`B)YGLPaLC5KMF8uzi!|eX7%}cxF z2ajjdeo9W;RI#{V>upwlsyxqQrv>ZAdp=r@_am*ehUaYQbjH%Mgu^?R`*&9`xHnzd_XCa9AdwWlr>A;I(o*`B-KHtQAHa+aQQcXVhQ>J zJENqzl1_YWoyQ72C+?0lN*b1EkvlD>t5uqD=ThWIg$7om4qx!Q_@=g1#(h<$DTG9ZqXk<;|cGxN2v2g;(KKZ z#@_j@g~nP(;DVMltGRYIF*+vKxpbYGYPh#{Z9Zqq{Tn$?V|r9#vk*}`fG!>Ljf>fA zl+buaq`JjdKy>s*2Qs{ zPL9iT71-G9N-WWa3^&#)5YDL57{&LfAOIbK%X2-LHA%1Fc~qnjpc_#`Hs`L~UdBz< zzUdZM0?Lr6wi!jxxJuxP#TOCB)$2n`1w$BI-en9L{BtC|$5V8CFx0u<$QpF`gbew6 z%QpxQ9>SMYU!wY~)JX?($w=MS0>)5vymDn*CThbHF0+`>F9-`#JFgj*cfvt_kx$MH zhQ;Fs?H4o)`0a!u;$}`{3?vL4uGA2(of#x~?5$S)+7`V)roYCT5RX6<;T@U(U;zx@ z*UWFRw#F6|5s$rx?O|iqMTdXefdSNXKx6xxKVmsP#Gsk2A5`t{So>6}dDmR1_BEav zCe|U-m4epk@EAgeImdDf1xPk{&PS|&;B`ASVPCGZQW>04vNTys6eq(XPanQ+x?GGS zRO`C6&2VvWwNErnK+YB!8;7Sjft_C*k}zMcatfo9h0=FVE?IMcFYH*09cwnXF~o#s zLy7tg8_Rpmcj@$o9n)!bSPTIrBNQ+Q_$OcyG#&bh1{2Gmmq~09bBfFu5iy;=crds5 zd)l~2Z2}Xx$by_z(TUH*;OBa;r5gfa+`lRtP$kPKh&fpT66a`otI6$%Rh(?eU_EH3 z^FTtvCV8k;)eyK>h@ij_leki4a>(n}8+tnx$K1v2wE7KBl_wf9qgs~yjxD>R?*=nS zY3?38o0YgE>2lt2>J>QtUPW3f0ws-oOSnF!9Ugm~!cMQwH2kF|;~v|}ane>sDAQMz zN2s#Zb_ekH`*wk!1qGnczx0i;VNV%b4g;l#iD=>zVY37VztgiDnIfU0$yh01k!?dz z>sq;sj!$5o-epY0<}qV%nox=Q*99)bmNEuVMp@62&1|lQTt&zbrfbCCe4!wUEljnF z;OvP-oNdmmxc|{c?#AdfpqxKRV|W?Kb37Pm=?0HAF}=FuoqsRx?(?CLZG($(YsS=2 zC>nM(QE-$(aKnitb2Ji)3K0M)YOhL`<7df*&TO{wv!8{iRa5GiFBQ&|Rze&?(`$&? z^w4?ifkDLOwD+}u5(auM^p}$Y{@0X*sOOw~Qk zBw}NetZC&N78H$j@#}{3Wq5DuFzZj5bBsLV4z4rTYpqF~$3O5}FOGz(r zh~BL?c^Tx5(KZ|$&GPNdxOho?1x+#V6UROh0S6mSA4N<95iMKi=MvK?8^z`!^7U`U zIHZ!TTj%#jahpGCHQWAXmXs7RyPkWgyi}S-ZEBzab%$$>snwhGnH>*+#E;K#MG1(w zVFa3H4HejDlVUkzQpcFXD4V~MWjcVNx{E(pkAn|sf5-GJjijP9UmkC@cCsDAr-`(v;&gc`Cda@1{M z33_T9SmhA7WJwPMYGu4T>AI9jzJO70wGRvG#(G|W_r_}?fYS?iQOSboNrRzK3F-Cp zjxMxpm@-r=hipS6XqnxTra+}k2V)r%)5s|7%$(*1Zxl@RskPRgs{fUY*?LgR!}Vz3 zRlDgo#sNIeWSkkpH*3@W@qnW+WB#t~$gIv#=sxeGWzR3B1DZ4^5I@MJjfOA79wRe) z;;7R`bH$~8?%nC-<%R+E`V-S+l(b;X^3@m|VP2}C9jY{DWofc|`%&Kmv(|er0W%Id zxdVE?GP0r;j06%;fIZUXsjQ~oRgnXQ6$+$wU`~qYu2H;Sq6Yay^kqhWvrk@VkIt5V z-PVZCp3}n}QDvo?_6cWd*E!Wm?g+bH@#?YobEPYE(TWkyyJ}Ox7&*DUHjBYjDr5cY6*^c*Q+V=V^G0#(XT9|UwRfx2UPtZ4blE0U@ZHJqqVnc; z2%7iN{(QhfCD-(A1_aA{DQnm33|@7ocj?2zi`T{<<^mD;Lie|0rK(H9D4+9*zlaH# zT=m#FDsSIBxm?%qiCH!In=(IYjJ|iYKTpq=ak5HTB^|R_O&sI%&-{T*n49M~A@n7GoyOJCE~HdB(`OyOymxin{Ep7|Sba43 z`lZm8zBDip$>O)1K+;A8O52wi&kM>xq%R6ZV)6*zP~;Fm3PSuKq7Jc;PoTo{^P4QL zIzs61>o@*d#>tD!2NEt%Qy15R^Hc5{w(+&=Pt6Y41qHxSa^~UHP#tO+{~3DR&L4dK z%A&J&_Un|eIPUzs=EjADPrdk1zApp|*=XczPW_vb#z1|YP{$u~CpWwtUb{3hn;rg4 z5u3udJ@ngvYGe}}En?h(wlH{-&%W;)tm5O6JKTa$wIPpG9z+K|uJYme2>M~A@B_lq zFl>_;G2gkWw}uy)r(OFY#5+mx9$|SPX#{D`^+A_nryX#G_-`-)#7(`CT%pIjpCVjB zpCGLwF`_UxGY7-Y92s7Bac63qb=ir$4zSh`6U5f?8Uua=`zN-?B53ZU&4+466%1Tuz-}q#0Im+9&&s0AvQ>hAK ze$-yxQAKoL&&!n>C_jQ#xXb7I_O#Lb{N@q2&b~GjlZ-;B2oJ!_%K`Zij7OD31|;U? zfnBh-=bT5J6e(AGBP4=k494A zq5bisIr^YlRJBH{@A)N@{Yy2-_V;T~R+H`~!HE|ypkdt_gB+*_kI)w4pSvgcK^!rH zx1yp~XB#i6%v%V-x7>bHI^>M`LyS_op4gNnRfcMh7on(liZxO4Ay)%B>RTDYysG_- zUfxuQZRGd^<8byf(!ckN>Tdf|oleM1ZUMpB9X@^ZVAa+LHni^^SJ^ivmcfSerCBpE za<`M^d8u0HH}JN@RBBZ2vjHg&y_JEU0Pe$D)t&BqN{kx4E+=lqphIqDEtAawfBk~X z`7}?CT9;Oo9U7mD85ysD&jBghYzBX6Bs1|}zzhyHqGUGuV4lk*Cz*;I|8>U_!{b)s zrTb+!rxWb(OGbSR9xs;Q@wMNnLO&|aZ&&VpWc_ww|%54t=7m* zc%KkT{Rn#*m#iDFl&cS}ca*~q0yJfb03(Yi@<>iuGbNFyn$d4jgWsH^5AQr|k66h5 zBzip6ED*oAH;5x;&D<-I9R-SNoj^B8z$c9gUe86;s2kR&pS~Y{A9+``&rXl`XSH0= z-_9?JFYy{*3QI)+z~#`qqKu_@2d}c*@{9sfxDV4nY8*!hyz7)2rbS!3K9FFWv){&z z8L`FhiJq-_^cvOoYSE=Z&I_ZQiP2oER%ImFsrTwJPHL)gYHOCHtqn-H(q7W9;LZ## z-^>)*t3FWF*KUPSD3==^VabKK4pTllL7P)!$b21J@_?E zvB{L-10#G)-c7(?O%sX^s0fMSU&9UEUl0cGF~f}cHrx{(eeA?BcyVr_`=y@U-6;kq zmgx`maMeRL-uMQz`?qF$wjZ~XFEgwAy2Uj~?eW%4p%$_e%fj_FZ%L%yo;hSrbt0#} zd+x)PM65ufQ5q$qi?}=Lr_u=}I?>qZ0V63+TPUJaILLN(gy{}kO(!KH)9YmKd5aXB zQ0rULv&pz~f6dfH9W8Tx5iPpaVQ%!r3ID6yCEi6TDL7 zTR2!mEUlzB>E&UcZ3jSokX`D3+T6?Bd^YC^4)OkMuk7E9jKS=NbDx=VQWlCGflVf? zw?L+;#x?WTVuvB}ul1!mV0G zDg$f+-#TqhMxdG~MAfUyXLzJSDW})hWhdB}4ZnKLA;#7Z5}ev3`lTigtX=dsf;V0X zx?sr{Mw2DjOcWpTyrJrg?%%FMTe-~)Ow2*#yC3eal)$rJu`}7ynPc-S$P8w~Vz4+Y zUl6zB)EImTi>1SQ|85&jw@ngca?pJ|?x7q~li>}Nz3oUPgbx_T81zjFNRaF4Y#Khk zdr{HUG%*-nLPvt0utnhbqVFILiY(6Lz2ObJMZ0$U(}XJ09B|6-*P6m^LYD5XpuOCG zi9N7X;CjObcxH7EXAfNtEHJBa-H?d*x_$Wyi8r+ULqS@~1E{+dlcm%wv=?k*v~@Qx zIAv}~u@jG6$kmTl_Z?ml-(Wm@07~tVt!i-dNs)`Sbn{R1T&Fiojucei5@P~`gAzyY zp;h;p8en>R>o_g7^AvsA(Z_*VBuYC7V{NExDviSqQtZPzA<;2Aj7yD!6E%zNp>MiIqD3!UQg8(?`G?GAh&|j35leZZghQVxs)0=#n%q>5p zA}yLxd|_a8BqbCatiKcsSaN;p+?yX?<_T2!bni#&%MBpIWrS4RN4P7|KJ=l&8!UN~ zMr^4#N1|M+bHEF}$By`HSfY35W8djt=_v(sPZK4y7!yp);>9EqgB8wr{MU!^z|{;m|-{ZI_RAH^d~YSKOVrJ?-CB+!;aSRrum5@orb0~20JEk zux$SlBVsBJ;HzfmDxD`U{%Z1{VY-!KarYvV=@^Z7T^e-S8k&3$7YQt+UB%ecM6&(! z&;<*$X=)Z;RLau)sEl?UAbsMT&V)g-MkVP`2@#{XO;-Ff18$gosX~!U#9hrKDcy{M zVp_-}{l}L0msKl%D+war6((HN6c@o1IOMB^CPanJ8@3aXU4>KW3~3S+T?e1(?2&A63vb))T)@uUJSnWs-ih7x552tg*52FlyJ9P!W)8 z1cp8(W5o1_P$Gys19H$QG0Z7P#H7T22?#JT6}hL6{59latpnihzGMj%)Or@h-gO}# z>^zAWKj=-5|4`5nT-j9FlufZ=h_IXw2{WKu0!o+eXaI0WM#N`oo$7>-wMZ6O7>Id< zGl$}1ll6m?ThB+bUGop!9pX7YNC_xO1!3q6oy-P5oYwx^iI}R(2mvF987FsqpB%(o zUznJS@aZC!7oMduLz#l?CTT}MUJIx^RK|Auzo*|CGmpgtxs55KDv!P)_E^Ny9Tf`j z-~M^EydJ9-$ubG;RC)6`QQ&kCAuvvPj+U z45ckvTuS>!0MR!Ol|1&<20s?jLWD=yeq0$rjrL|d_i$^;8#--HRrT?-#?A6I!~Tga z(JtNiq4l5l&}U(1b2d7%{UMb<^YnjfVN^-qo%$T^R42yhSo0mfeEj~b9Ya9KE8Gfv zElC%N$rShHWH-*K4r~TGD1}-YFsjt6B$Rc0fH+w_c|e>G^apsfyQTM^2LJkc|sr9IzYbVm6nJAH4C z$fDPQ=vWV*4?lr>x39_1P>VDB5(Pw8I#lzKS`2gnp4s?!3SqMMM1(8zVK=I3z*$!# zeBgs-V2Lhw%I|mWm^_;ie3Cf2mGXw4D!J6zy`o^Oq*KaL^ z%*d3Kl%Zi^arLn~QBy4rBL<%oOJqdjdSxydlExjUMW``ew$%Hdc1<3LsK*SmV?Q}Q zoHIavC#=)uGpf=Gi!4{I6ZS}E&#H9I{(#r@z*3k|AeA)!zTf^KGt~^w0m%UgGlhe& zG2E&keJ`y;{TD&0bjr|Y3ZjCd*&W~czOuei(`z^zH`y(=Rg*elJ`65Jk^BX9S6LCPdGX zXg+csVm|oM_G`-w)rn2#F*f1vTt5k|wI)Z-p~z<{6;jBheyDcRqa3;rh?%1trnR~B zXjS8l!(oq-33)_eF)Wsmy3aGKRtgN_`x<%91}$c7+;a2z&HVEY{`DTR&3`UgEQ_J< zt7PyZ<-6yu*61+%%kQ1FpWi4eKSem|3#diBNX!)1Q`uJ>~ob^c@U zoj+Ew&~$Hg7ntb?W7O8dFBd!DevmI*`w88EyM)76t1#lybz2`DaD28(?D*_t^!iwk znL&4-(t+MvV2^M2^Z)Fx1!7|{gS+Yc_SuX6@%I;@j`G&p=P73Iwi!n`G^6gB+|UsS z>#|^7?+ocbnxlz+4XYsxn=Qnq1Yu|Ucc%IO&-Er9x8ks`_4=+F>>{S5MmC?Y$8F>hk2|06 zX8l6n;pV`AZ}SaYszXOexs}^c(ecIm&!Pn{+aK9qufPNm==JcAZ$A8voV+@XB>=iB zSyOv^`;S_CpMIVjd)Y)51kF@46Ve*d{^H*+=<|FNkP{6Js|#6y(B zn2IU%?B% zvOC<-@9ah+KfloHT69P26*b#wT7b5MUHetH0D@*L#q@`l$J9Tgjx@be?`VbUMz#H< zld<67D%(D`2?QQ}EsB7ssuDS>S2tMy=86utw(ex-I6u6brDW%_z+b?`Z?1W;R~Rg@ z|2b>)6S^rJi-oMZ*$Gdc%VO`mG^A_NPa7Ku3>LhZlV*+x>(Zhwo0*g2+k|OXwY5a9ld^Xi+Y^el80T(kfKUHDRoJgw- zV^K-&G#XE#Tf~bs=Y`Aq6+2gELhnz4J16uiNenXZDMMxhkTQgRX zZ}V26vE34vcC&qIwKT^pW`0|vol|C3`8gt!PZ5I$ca0le^oLoi4r3D+oj*<{GXCOm z#Gdg_UYA8MHX1K@zwDi%)Q5ik$7bG%xmCeJCI?imv{Z9u(P6U%j9Y!lW;3G15+DveL{r3-v2C|Rh8T3HZhFy zH;4dZma>-={;UUb{lVsk?NT;=%O6c8(~j9G8;)Z;0}SvOpSZnJJJ!gWX(P}^0H7H3 zP-LC^Xk7gc57x!Te|Ze>q<)vm9CJU=cvQ9ceR*Wo4pK*=ilXOsf^bWO8(cEKx#GW> z`7>)wP#kj}REBzNV03HcR9P5g7}bcu?oB3g>y545+8Gh7ENxf4hE`A_V(7NnbS3iv zjluJWT*AYxd$xdlc{9`ISwM1LptVX9^9 z#cU%Nb`7UvDsNIP@?;hA>jr*cHVn^ zi06(1Gvvi~m33y{agcsL(C^c$QlV}7h5i8v*~erSJC{tm$oY?n#`>o?>Qq@6Mn?;*~`Cl$ius)d}29A^)seE*gZ?% z1RIuS={}__(!BZ@GO|8sRussOu5*+5r9*>NjZ6w*)2304_`ja0a7)GV!B3+!L|0F` zed8}`I-6zK3hJofh1GABTjWKoJZeQaXUm1)rWpEq3uGr!>RgXA5w{M0M;7xHEa~I< zVBKE?W%CswzkF@~B#9_h(Wz=Zu(m%>U+T%@k2Wim#pKK% zg%f8MlvRrv7-?PGP=`*uDKj4VJP*OSKXMQv9iKIfF_o$oKJ}nd_ZHs9K9?!R)=j#1 zcB{m#dz_$+YqyPl;W7RGP=WC9bW^vO2l>yJIMyF50lIYfznVJlaJJhnj@z>+jZ(8{ zi5c3eP%~<@MeWgw*_PT7MW`*+8dWv>2o)YhQT3?3ca6p#C03Lu6(h0No9D%Qz4;@5 z>D)9z$rB47#&9SW-}2R=syu!?bloi@Det`f2BtjeF95 zMo)d0nU`(o7T)G_Yn}aMYuU#~4(&FV$sv z50P(%a;=^|Vw(E?hUN1l$fkHN@pv&3oZ^zqo=Yv!)SF`Wa4cZ;k5z$jt?5OX!tlV+ znOQqai{fti%+p?F9NI=^QUxBj?W$eQ^~&K$V2%+A&*ertQxwJ8jLlEL8n42_1URTxMvFK7r`NBZrSA=#3{fh0kZfBJ z-XLvdIIP;H9!mw4a_y%Wji6uHD4I3+ukgHvLSP2$?g|RV+@r^_0;H0L@M?2ut0X*N zsob>{n@wBPc$DI*e5z4x!CBx+YNPu(;E-o-iVG>U%)c(XTH%xn!)t*&W2GWRVGd`^Yo4_!3;&c)nY z(L_ANTx)yS)bbTeqRNt$^l0Rp%dXAMUt{?gT^~Inyf_m}1QU5MESE za+k^fg`6N&8ni9dTm1OMDvP<$hJO^)nA9nEg8FaX-YFx=$bVNn4tHp~8W#MAyI23O zChJO%3U#g#tky%)yNi|zo|y9_Z+>LQXBrm98W!rEIP;Xh!6i{;WD-M|(`PH(rX&LU zkm`LusiDdq6M#|M;DpYhh|}DB579)ee9K%Xt+#H>i@i%qiapp7BC|**gVYTZlt|;gi)X&ePwcU!o zxcT5@Be*WhXQXLliXuZbP$goN`o5DqmR!dxC$#8-omU#}k?CbT_lvnM_+EWUj4(nq zQiL^lp{<*tuQ#Q_WIk7q6)_UiJ*gBt7kM6@CbBCJXYG%9u%8m_0&565Fh~NXT*uVg z-}o@QWXKvM792Cg_0WFoZN_*7(FvuxdGpn_Gt-Vm^13V|dX+k{i%US%Htm9H{B*?l zTg%1go5=LC%OVz@ouAf))~ z{MapkNt4@LmadUPl}o+dt$p>p0WvJ<{4V1X$FU}N&}&Cj{-Omv8fVwCfosDQsAIK3 zRkc-UOGXPY00tRwkl>EX^ztKv4un#xl`zhk8u|1%*HG_i_?v80Cb3TRfm>c~^9>(h zue{4ILYT~Pi4A{>eQRhE03oG`JsTJr$$9OYtXO?bm2CW76_Zwvj@l zZsul%yHfUKl!{TFfu^{R%41ae?7EBMT`9#F$sUKRBD+L*m-y zooC#Ex7U;+gXn$jyV8pdA#)KjK`D+}!;qq%RhMR@_?i8p)aw*{__z7SUx6CbLMP?$ zvLacx_{>BDFjq!B1fQ5aX$%ouButfQV&P1rzvS&d+?Iaae_qqN$1JXmFii~f=-Ip| zjaflh3>WBL{8*7y)F9;oI~SLj%JK1myP`LytPOEhI2GEomFPNW455uE1?WjQCFNgw zb4Q$u{dk&}Tfvc6_<(yh|4+PYDZalkj&5sAP;*eB#}J*ySU(mN)gY}Y>ofm+wz#Q3YEVX}6iIH#^4SyfQ$MQ0pnOFwT{q?H=xV^1Uf}%RZlA#n==7OxR-$ zOp_!T!!qfctuG(4Te0+JrOTpUoikP_K_M)up4rU#Xq?nl-m)p;Owm!C3H?wJ%^IA(r%>}eTdzYXbOvp<$Ix@{pAEk9(x-f}u zuf&Q@-4@#07PORu$)fn8=W|n`vIk?5V0k~PVJ6zoK1*S3k-W~A2Wf^p+8k^XYy9=m zp(YC-z#$$A&w_6<;ytZfmnd|AHr^1!R(svA9a#?*`2hyWay}CrQqx~AS^SVoTQd?o z5-Gu9GZ%s8!<5(g^v8YFu5^mfwLFe2uly4;wXIwrRFtn)t}v6MQ`K-=6;cm&M~<83{rT4UMQAZXy* z(C#(+9|Y#AfW1JUFNJN9&{Wv(vVwI(0OZG)h<7Oh5ywJ5z_9-maFl+7UXb{?JJbo*Kc^M z7QD<tL9d$Ow zuoq)82<7uh?pLF^i-PC$`-(Ee&}H$Wqs;}$!TEC6hW9NKiHV81owdG4p*Y3Q zRB~Iyn5qD8P8)MTm?pbL+I`m6pXug&JjbE{X)&DjODfSNPQzV=&ZAhAXFVBm#~4y59c?df3F(?4Of1I>Gr(V=&R9}+xvWFET={T?WNV(*LQVs zUpvW@L}}3GWVez==YP+LJ81Ev=JE$E=V>4LbuUR5X8_RjIw193?toq3$F*k89hWUmjxYhk7CSSd_n!vlNDV!vQOc(rOwsEb31bD zdjeK*<+NG6J2Wb;4{6j$yP?RmI_Z}ZS(!hrs^TI#QNDUD?h4orC@iM0)yWFY^64`w zo_Yc)9ix)-n3hx4tB)vtTwzD_JAlpYxLPXJs&!w6MU^%1r5t)uDPRbl%Rzyqhb^3u z!NaUa!i}AAwfOZ`LfP(%PQ2`A)3ll$DFf-)(0fJ<@=7~8FR?F3`D1*S*lb%yn03}i zK3&qSg0YxP4kID<>gj$d^YN|<8}k(^Rh)3D1b*c?!++#1e|*!tH^YXTT(X62McK03 z?7twfHAa>N&V+WD(bm@rVB!Moi5ZqC)jGlS(aesiGBMd)w=3Y%t9-2!t5?!>ur=Pf zro~4I;69Ee;a~OoytA865z7B-8K9AgdNOi^l_fF}Jd_G_QH3#wmcPHG3OK2(Eq*Rz zB%&tQUumpSgVqLt78M*+J!X*SYPMBLhAsMQ)De%^ibr{aDK&ujd1j09yx~CWLQ-g| zC&H9LioU*sflM*JfihoF3GlI#cN+2x{$f!bT- zKg5K^H`Dkjs0=@1%O_nos<77DMeM836U56c5)V-1lQ6T0;o1er+Ajcd5RoORY~Oe` zl;T5f^BkZiVXXUNAHPeF^2m2f_iNGa$UyDtVVVLD!_IK~h-?wJJeKJNMsC=uZg*|% z-jn`$H(lPIr@W3O$KQa#haFOK8&bRxF8%=fz&o# zD*sv-boAtIv&~37RQ+Znt88BjDdH`wC}3x&0pLz%UNe_>zaFIIw0pKoin(6+^sf=7 z2bSEuW`)NuV# zv0WGyrv&gRs%J8jt@Qz4xX8Z%{GDTxO`vHoCyIPSg}OyW+JKSIU+?PR1p$MP%9(Skr)8mh^S_oo93Gkpzaw?gZyC`0 zBVEmSVQOxD0AL*O^=Rlvycn0+F+BVUu;)9)@Y~{Rv!P|8>bc^)c+VR{g<^8`) zZfAv@)MKfkBxNot@;<_}J1?jl92a1{DyI$U*N5}brcZ&Y{)MYmmfvqGJ{1YIhb4+< z+^mCQF3DdqF%Y^hXV8aG6&0l$?MW?DSv)Um5eyPImah*q!m?;b#6JQ229SZg&q-OJ z24m=Z`sHoLgSjAeX%WoJBkqw}%&F>y8=-^HlX$8rGT}vuSAHN(_vs8juz4xS4Sct{ zEXoMS5GjQtp^?=$lg>ukL-NOrd&5Vv&5QTP|9M(Saxlr$iz<2eJU@x<_numD9%l=d z8gre`NY{u4#3>RNl4QM*f4uX!%xFvXl@k4Ajt=X z6Mfz92+0W=S7R|BRj7LA-x{p^ohu%7as-G}*&$1yv-n`fvnJn4Z zHnw76?;q14Tg_`H+il|~L_q3H zRVNN_8%TOiLY?{ay1^WH2sWC^i#*xSl6UnFZcA10jYzHSb;QkNJ12Bjg4(JXSxZt{ z|IT%SZKOUm1Tvv@*~RKU0WaWRL1i8M1tV$lXBR)|bTP@xd9~1d^CjLz?yJbHBxEB{W$x%Y0DvU8v<*y)fuSTgG?s|8Z_}6LxgVp@5XsZ4R z7cxn~bR&MHsUC_1rigz3*5-f{W zrWx0Y)FOJ1Ci@#TUB3ke3V7JuYiq&8$$B*Nqb5cHAaOwdwpGkfC6FS)N-Ad25e1^k*>r;xD{RQ^VgBPg`Dmd%l!V2Idl4&F)XHOjQd$+{m*=ELuH5 z3^-v>B5#O)_&mvH|f;dyX$EM5#3~LIE3P!qXE|Og$3i}C z%MpZHnYrz^ENL8OMkE!Wq+kUqzjJtHXO8Md?Ig};mgq_ zrlv7v{MO4082{JSf!*p39yW)SyAX7T;!#|J{p$ZEToP0E`I~|VmTF^zu?j)_^aS5$ z+w^^%R~g}ffK$rA~@b(k=cf1~?B``oWTbo6U>dNT;x z#*YR~1E5b$2gxnY-_~y!Z--nMl4Jq`4AwywmsGV@gqMl6;6ry2KuCe?{cYR$q&Af$ zzD=g^XSQ0)UH5^~6rP&U!p_FjvXp-~$o7v&Ex#;2=n7=Wl+; zv?c3qMI}RUi*x|h(=`gsP+y^6w`omfUnjgwgI#{SE#0}fj@VUMWKF>w01nu!TMoPG zXP2{c@uIGcB5H|tjj5{dX8NS4m4C=Oc z9_#B_7ZG2xqrKx%KTzuj`o{2?DWi}{;HgB;y`hx+B@w2|y_TtJ8Xp_Zf$9Sa5@D3O z7!p1Ut+^&);fkayr^+%~wwJQtlK!jy?VzfXb28nq=N@H19Z~hK;exo?8vYHVwFdtZ z$D373uIPb)=BCl-QVcq0uGk(F<%ASxz662(LOU(wI7x>XtHFf&lRYE=eqI^_!kG7* z;(soPDNvK>YzrEz9btY|g+X@xh!#7bxU{5s8>3bc#%j>v|CK4b`YzE=X#fb6Dh%ay#2Nw-6VGeo1Uo9;=($@WYn@0n|8zlSVV~Q zet@5%5`*~nCw00ogL%~~@VT<7X~GPe-4qn`EsM|AT8$0SXO`sIdjM`XxJM0OZXgBv zCB^gCOwT#wj0|YgF9iH+PA>dwPM-DeaHjTZ{@2Dl?PvY|Z@WZ|KC;VL|F6q<_R|fg dx^DnG4$+!bdiSvIxR-+bxTj@s_Y1@>{692N30VLD From bbf114fdd59826266fb03a43e68ed4b9e635adec Mon Sep 17 00:00:00 2001 From: gsmith-sas <65406958+gsmith-sas@users.noreply.github.com> Date: Wed, 8 Oct 2025 15:32:55 -0400 Subject: [PATCH 20/20] Added CHANGELOG.md entry --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5ac492f..291bae07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ # SAS Viya Monitoring for Kubernetes +## Unreleased +* **Metrics** + * [FEATURE] A new sample demonstrates how to extend SAS Viya Monitoring +for Kubernetes to monitor the SingleStore instance that is embedded within +SAS SpeedyStore. This allows administrators to monitor their SingleStore +cluster using the same Grafana instance that they use to monitor the rest +of their SAS Viya deployment. Refer to the [SAS SpeedyStore Sample README](samples/speedystore) +for more information. + + ## Version 1.2.42 (16SEP2025) * **Logging** * [FIX] Corrected handling of unavailable API endpoint in deploy_opensearch_content.sh