summaryrefslogtreecommitdiffstats
path: root/python/mozperftest/mozperftest/metrics/perfboard/influx.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozperftest/mozperftest/metrics/perfboard/influx.py')
-rw-r--r--python/mozperftest/mozperftest/metrics/perfboard/influx.py188
1 files changed, 188 insertions, 0 deletions
diff --git a/python/mozperftest/mozperftest/metrics/perfboard/influx.py b/python/mozperftest/mozperftest/metrics/perfboard/influx.py
new file mode 100644
index 0000000000..4f7e27072c
--- /dev/null
+++ b/python/mozperftest/mozperftest/metrics/perfboard/influx.py
@@ -0,0 +1,188 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+import datetime
+import statistics
+from collections import defaultdict
+
+from mozperftest import utils
+from mozperftest.layers import Layer
+from mozperftest.metrics.common import COMMON_ARGS, filtered_metrics
+from mozperftest.utils import get_tc_secret, install_package
+
+
+class Influx(Layer):
+ """Sends the metrics to an InfluxDB server"""
+
+ name = "perfboard"
+ activated = False
+ arguments = COMMON_ARGS
+ arguments.update(
+ {
+ "dashboard": {
+ "type": str,
+ "default": None,
+ "help": "Name of the dashboard - defaults to the script"
+ " `component` metadata. When not set, falls back to"
+ " `perftest`",
+ },
+ "influx-host": {
+ "type": str,
+ "default": "perfboard.dev.mozaws.net",
+ },
+ "influx-user": {
+ "type": str,
+ "default": "admin",
+ },
+ "influx-port": {
+ "type": int,
+ "default": 8086,
+ },
+ "influx-password": {
+ "type": str,
+ "default": None,
+ },
+ "influx-db": {
+ "type": str,
+ "default": "perf",
+ },
+ "grafana-host": {
+ "type": str,
+ "default": "perfboard.dev.mozaws.net",
+ },
+ "grafana-key": {
+ "type": str,
+ "default": None,
+ },
+ "grafana-port": {
+ "type": int,
+ "default": 3000,
+ },
+ }
+ )
+
+ def _setup(self):
+ venv = self.mach_cmd.virtualenv_manager
+ try:
+ from influxdb import InfluxDBClient
+ except ImportError:
+ install_package(venv, "influxdb", ignore_failure=False)
+ from influxdb import InfluxDBClient
+
+ try:
+ from mozperftest.metrics.perfboard.grafana import Grafana
+ except ImportError:
+ install_package(venv, "grafana_api", ignore_failure=False)
+ from mozperftest.metrics.perfboard.grafana import Grafana
+
+ if utils.ON_TRY:
+ secret = get_tc_secret()
+ i_host = secret["influx_host"]
+ i_port = secret["influx_port"]
+ i_user = secret["influx_user"]
+ i_password = secret["influx_password"]
+ i_dbname = secret["influx_db"]
+ g_key = secret["grafana_key"]
+ g_host = secret["grafana_host"]
+ g_port = secret["grafana_port"]
+ else:
+ i_host = self.get_arg("influx-host")
+ i_port = self.get_arg("influx-port")
+ i_user = self.get_arg("influx-user")
+ i_password = self.get_arg("influx-password")
+ if i_password is None:
+ raise Exception("You need to set --perfboard-influx-password")
+ i_dbname = self.get_arg("influx-db")
+ g_key = self.get_arg("grafana-key")
+ if g_key is None:
+ raise Exception("You need to set --perfboard-grafana-key")
+ g_host = self.get_arg("grafana-host")
+ g_port = self.get_arg("grafana-port")
+
+ self.client = InfluxDBClient(i_host, i_port, i_user, i_password, i_dbname)
+ # this will error out if the server is unreachable
+ self.client.ping()
+ self.grafana = Grafana(self, g_key, g_host, g_port)
+
+ def _build_point(self, name, component, values, date):
+ value = statistics.mean(values)
+ return {
+ "measurement": name,
+ "tags": {
+ "component": component,
+ },
+ "time": date,
+ "fields": {"Float_value": float(value)},
+ }
+
+ def run(self, metadata):
+ when = datetime.datetime.utcnow()
+ date = when.isoformat()
+ metrics = self.get_arg("metrics")
+
+ # Get filtered metrics
+ results = filtered_metrics(
+ metadata,
+ self.get_arg("output"),
+ self.get_arg("prefix"),
+ metrics=metrics,
+ transformer=self.get_arg("transformer"),
+ split_by=self.get_arg("split-by"),
+ simplify_names=self.get_arg("simplify-names"),
+ simplify_exclude=self.get_arg("simplify-exclude"),
+ )
+
+ if not results:
+ self.warning("No results left after filtering")
+ return metadata
+
+ # there's one thing we don't do yet is getting a timestamp
+ # for each measure that is happening in browsertime or xpcshell
+ # if we had it, we could send all 13/25 samples, each one with
+ # their timestamp, to InfluxDB, and let Grafana handle the
+ # mean() or median() part.
+ #
+ # Until we have this, here we convert the series to
+ # a single value and timestamp
+ self._setup()
+ component = self.get_arg("dashboard")
+ if component is None:
+ component = metadata.script.get("component", "perftest")
+
+ data = defaultdict(list)
+ for name, res in results.items():
+ for line in res:
+ if "subtest" not in line:
+ continue
+ metric_name = line["subtest"]
+ short_name = metric_name.split(".")[-1]
+ short_name = short_name.lower()
+ if metrics and not any(
+ [m.lower().startswith(short_name.lower()) for m in metrics]
+ ):
+ continue
+ values = [v["value"] for v in line["data"]]
+ data[short_name].extend(values)
+
+ if not data:
+ self.warning("No results left after filtering")
+ return data
+
+ points = []
+ for metric_name, values in data.items():
+ try:
+ point = self._build_point(metric_name, component, values, date)
+ except TypeError:
+ continue
+ points.append(point)
+
+ self.info("Sending data to InfluxDB")
+ self.client.write_points(points)
+
+ # making sure we expose it in Grafana
+ test_name = self.get_arg("tests")[0]
+ test_name = test_name.split("/")[-1]
+ for metric_name in data:
+ self.grafana.add_panel(component, test_name, metric_name)
+
+ return metadata