From cd341dc1ed444274da7d32757587f33f3dd02dc6 Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Mon, 11 Nov 2019 22:15:13 -0600 Subject: [PATCH 01/10] Add failure per seconds as a series in the chart --- locust/static/locust.js | 4 ++-- locust/stats.py | 26 ++++++++++++++++++++++++-- locust/web.py | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/locust/static/locust.js b/locust/static/locust.js index 60dc6e6b1c..ae421ab206 100644 --- a/locust/static/locust.js +++ b/locust/static/locust.js @@ -137,7 +137,7 @@ $(".stats_label").click(function(event) { }); // init charts -var rpsChart = new LocustLineChart($(".charts-container"), "Total Requests per Second", ["RPS"], "reqs/s"); +var rpsChart = new LocustLineChart($(".charts-container"), "Total Requests per Second", ["RPS", "FPS"], "reqs/s"); var responseTimeChart = new LocustLineChart($(".charts-container"), "Response Times (ms)", ["Median Response Time", "95% percentile"], "ms"); var usersChart = new LocustLineChart($(".charts-container"), "Number of Users", ["Users"], "users"); @@ -159,7 +159,7 @@ function updateStats() { // get total stats row var total = report.stats[report.stats.length-1]; // update charts - rpsChart.addValue([total.current_rps]); + rpsChart.addValue([total.current_rps, total.current_fps]); responseTimeChart.addValue([report.current_response_time_percentile_50, report.current_response_time_percentile_95]); usersChart.addValue([report.user_count]); } diff --git a/locust/stats.py b/locust/stats.py index 8b227c4a47..8b56a694c5 100644 --- a/locust/stats.py +++ b/locust/stats.py @@ -178,6 +178,9 @@ class StatsEntry(object): num_reqs_per_sec = None """ A {second => request_count} dict that holds the number of requests made per second """ + + num_fail_per_sec = None + """ A (second => failure_count) dict that hold the number of failures per second """ response_times = None """ @@ -231,6 +234,7 @@ def reset(self): self.max_response_time = 0 self.last_request_timestamp = None self.num_reqs_per_sec = {} + self.num_fail_per_sec = {} self.total_content_length = 0 if self.use_response_times_cache: self.response_times_cache = OrderedDict() @@ -286,6 +290,8 @@ def _log_response_time(self, response_time): def log_error(self, error): self.num_failures += 1 + t = int(time.time()) + self.num_fail_per_sec[t] = self.num_fail_per_sec.setdefault(t, 0) + 1 @property def fail_ratio(self): @@ -330,6 +336,15 @@ def current_rps(self): reqs = [self.num_reqs_per_sec.get(t, 0) for t in range(slice_start_time, self.stats.last_request_timestamp-2)] return avg(reqs) + @property + def current_fps(self): + if self.stats.last_request_timestamp is None: + return 0 + slice_start_time = max(self.stats.last_request_timestamp - 12, int(self.stats.start_time or 0)) + + reqs = [self.num_fail_per_sec.get(t, 0) for t in range(slice_start_time, self.stats.last_request_timestamp-2)] + return avg(reqs) + @property def total_rps(self): if not self.stats.last_request_timestamp or not self.stats.start_time: @@ -370,7 +385,9 @@ def extend(self, other): for key in other.response_times: self.response_times[key] = self.response_times.get(key, 0) + other.response_times[key] for key in other.num_reqs_per_sec: - self.num_reqs_per_sec[key] = self.num_reqs_per_sec.get(key, 0) + other.num_reqs_per_sec[key] + self.num_reqs_per_sec[key] = self.num_reqs_per_sec.get(key, 0) + other.num_reqs_per_sec[key] + for key in other.num_fail_per_sec: + self.num_fail_per_sec[key] = self.num_fail_per_sec.get(key, 0) + other.num_fail_per_sec[key] def serialize(self): return { @@ -387,6 +404,7 @@ def serialize(self): "total_content_length": self.total_content_length, "response_times": self.response_times, "num_reqs_per_sec": self.num_reqs_per_sec, + "num_fail_per_sec": self.num_fail_per_sec, } @classmethod @@ -404,6 +422,7 @@ def unserialize(cls, data): "total_content_length", "response_times", "num_reqs_per_sec", + "num_fail_per_sec", ]: setattr(obj, key, data[key]) return obj @@ -427,7 +446,8 @@ def __str__(self): self.min_response_time or 0, self.max_response_time, self.median_response_time or 0, - self.current_rps or 0 + self.current_rps or 0, + self.current_fps or 0 ) def get_response_time_percentile(self, percent): @@ -639,11 +659,13 @@ def print_stats(stats): console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7s %12s %7s %7s %7s | %7s %7s") % ('Name', '# reqs', '# fails', 'Avg', 'Min', 'Max', 'Median', 'req/s')) console_logger.info("-" * (80 + STATS_NAME_WIDTH)) total_rps = 0 + total_fps = 0 total_reqs = 0 total_failures = 0 for key in sorted(six.iterkeys(stats)): r = stats[key] total_rps += r.current_rps + total_fps += r.current_fps total_reqs += r.num_requests total_failures += r.num_failures console_logger.info(r) diff --git a/locust/web.py b/locust/web.py index 3d8342debb..348e6b849e 100644 --- a/locust/web.py +++ b/locust/web.py @@ -134,6 +134,7 @@ def request_stats(): "min_response_time": 0 if s.min_response_time is None else proper_round(s.min_response_time), "max_response_time": proper_round(s.max_response_time), "current_rps": s.current_rps, + "current_fps": s.current_fps, "median_response_time": s.median_response_time, "ninetieth_response_time": s.get_response_time_percentile(0.9), "avg_content_length": s.avg_content_length, From aba515393fa77406eb45081dcd87929ce5439a11 Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Mon, 11 Nov 2019 22:33:09 -0600 Subject: [PATCH 02/10] Fixed string format in StatEntry.__str__ method --- locust/stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locust/stats.py b/locust/stats.py index 8b56a694c5..d6f7ffc1bc 100644 --- a/locust/stats.py +++ b/locust/stats.py @@ -438,7 +438,7 @@ def get_stripped_report(self): def __str__(self): fail_percent = self.fail_ratio * 100 - return (" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %7d %7d %7d | %7d %7.2f") % ( + return (" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %7d %7d %7d | %7d %7.2f %7.2f") % ( (self.method and self.method + " " or "") + self.name, self.num_requests, "%d(%.2f%%)" % (self.num_failures, fail_percent), From 21ecd4b892b6ff9259391099726f52dd72e71597 Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Mon, 11 Nov 2019 23:01:15 -0600 Subject: [PATCH 03/10] Add test to current_fps property --- locust/test/test_stats.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/locust/test/test_stats.py b/locust/test/test_stats.py index b0f8402918..ebcdcd1415 100644 --- a/locust/test/test_stats.py +++ b/locust/test/test_stats.py @@ -63,6 +63,16 @@ def test_current_rps(self): self.stats.total.last_request_timestamp = int(time.time()) + 25 self.assertEqual(self.s.current_rps, 0) + def test_current_fps(self): + self.stats.total.last_request_timestamp = int(time.time()) + 4 + self.assertEqual(self.s.current_fps, 1.5) + + self.stats.total.last_request_timestamp = int(time.time()) + 12 + self.assertEqual(self.s.current_fps, 0.3) + + self.stats.total.last_request_timestamp = int(time.time()) + 25 + self.assertEqual(self.s.current_fps, 0) + def test_num_reqs_fails(self): self.assertEqual(self.s.num_requests, 9) self.assertEqual(self.s.num_failures, 3) From 20ccef5006478a900a93c39d8fc382c116efe996 Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Tue, 12 Nov 2019 08:09:27 -0600 Subject: [PATCH 04/10] Include fail/s stat in print_stats --- Pipfile | 11 +++++++++++ locust/stats.py | 4 ++-- locustfile.py | 11 +++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 Pipfile create mode 100644 locustfile.py diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000000..2d10bb9548 --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[dev-packages] + +[packages] + +[requires] +python_version = "3.6" diff --git a/locust/stats.py b/locust/stats.py index d6f7ffc1bc..51bdb13343 100644 --- a/locust/stats.py +++ b/locust/stats.py @@ -656,7 +656,7 @@ def on_slave_report(client_id, data): def print_stats(stats): - console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7s %12s %7s %7s %7s | %7s %7s") % ('Name', '# reqs', '# fails', 'Avg', 'Min', 'Max', 'Median', 'req/s')) + console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7s %12s %7s %7s %7s | %7s %7s %7s") % ('Name', '# reqs', '# fails', 'Avg', 'Min', 'Max', 'Median', 'req/s', 'fails/s')) console_logger.info("-" * (80 + STATS_NAME_WIDTH)) total_rps = 0 total_fps = 0 @@ -676,7 +676,7 @@ def print_stats(stats): except ZeroDivisionError: fail_percent = 0 - console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %42.2f") % ('Aggregated', total_reqs, "%d(%.2f%%)" % (total_failures, fail_percent), total_rps)) + console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %42.2f %42.2f") % ('Aggregated', total_reqs, "%d(%.2f%%)" % (total_failures, fail_percent), total_rps, total_fps)) console_logger.info("") def print_percentile_stats(stats): diff --git a/locustfile.py b/locustfile.py new file mode 100644 index 0000000000..adfbe3cf41 --- /dev/null +++ b/locustfile.py @@ -0,0 +1,11 @@ +from locust import HttpLocust, TaskSet, task + +class UserBehavior(TaskSet): + @task(1) + def index(l): + l.client.get("/bundle/") + +class WebsiteUser(HttpLocust): + task_set = UserBehavior + min_wait = 5000 + max_wait = 9000 From a08481bbe5ca7548ea3821b764cdfa18efe42502 Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Tue, 12 Nov 2019 08:23:48 -0600 Subject: [PATCH 05/10] Renamed time series to 'Failures/s' --- locust/static/locust.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locust/static/locust.js b/locust/static/locust.js index ae421ab206..8cbb6ffab0 100644 --- a/locust/static/locust.js +++ b/locust/static/locust.js @@ -137,7 +137,7 @@ $(".stats_label").click(function(event) { }); // init charts -var rpsChart = new LocustLineChart($(".charts-container"), "Total Requests per Second", ["RPS", "FPS"], "reqs/s"); +var rpsChart = new LocustLineChart($(".charts-container"), "Total Requests per Second", ["RPS", "Failures/s"], "reqs/s"); var responseTimeChart = new LocustLineChart($(".charts-container"), "Response Times (ms)", ["Median Response Time", "95% percentile"], "ms"); var usersChart = new LocustLineChart($(".charts-container"), "Number of Users", ["Users"], "users"); From c7478ed69eefd9ac2012cf93a08a25cc6a7fcd87 Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Tue, 12 Nov 2019 08:26:02 -0600 Subject: [PATCH 06/10] Include 'Current Failuers/s' in statistics web page --- locust/templates/index.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/locust/templates/index.html b/locust/templates/index.html index e43e6cd20f..c3b5a85473 100644 --- a/locust/templates/index.html +++ b/locust/templates/index.html @@ -121,6 +121,7 @@

Change the locust count

Max (ms) Average size (bytes) Current RPS + Current Failures/s @@ -138,7 +139,7 @@

Change the locust count

Method Name Type - + requests @@ -238,6 +239,7 @@

Version <%= this.max_response_time %> <%= Math.round(this.avg_content_length) %> <%= Math.round(this.current_rps*100)/100 %> + <%= Math.round(this.current_fps*100)/100 %> <% alternate = !alternate; %> ]]> From 01b26a37b5cf59aa1b6f33a0713e1c63d900587c Mon Sep 17 00:00:00 2001 From: Ale Cunha Date: Tue, 12 Nov 2019 08:26:42 -0600 Subject: [PATCH 07/10] Changed column name to 'failures/s' in print_stats and fixed width --- locust/stats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locust/stats.py b/locust/stats.py index 51bdb13343..f25a9ffab9 100644 --- a/locust/stats.py +++ b/locust/stats.py @@ -656,7 +656,7 @@ def on_slave_report(client_id, data): def print_stats(stats): - console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7s %12s %7s %7s %7s | %7s %7s %7s") % ('Name', '# reqs', '# fails', 'Avg', 'Min', 'Max', 'Median', 'req/s', 'fails/s')) + console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7s %12s %7s %7s %7s | %7s %7s %7s") % ('Name', '# reqs', '# fails', 'Avg', 'Min', 'Max', 'Median', 'req/s', 'failures/s')) console_logger.info("-" * (80 + STATS_NAME_WIDTH)) total_rps = 0 total_fps = 0 @@ -676,7 +676,7 @@ def print_stats(stats): except ZeroDivisionError: fail_percent = 0 - console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %42.2f %42.2f") % ('Aggregated', total_reqs, "%d(%.2f%%)" % (total_failures, fail_percent), total_rps, total_fps)) + console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %42.2f %7.2f") % ('Aggregated', total_reqs, "%d(%.2f%%)" % (total_failures, fail_percent), total_rps, total_fps)) console_logger.info("") def print_percentile_stats(stats): From 596327a0181a9ee57c9007aa0d5acb6d9859d941 Mon Sep 17 00:00:00 2001 From: Alex Cunha Date: Tue, 12 Nov 2019 10:15:28 -0600 Subject: [PATCH 08/10] Remove Pipfile --- Pipfile | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 Pipfile diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 2d10bb9548..0000000000 --- a/Pipfile +++ /dev/null @@ -1,11 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[dev-packages] - -[packages] - -[requires] -python_version = "3.6" From 8a27b21897a3cc04309598edcdecc865b9add515 Mon Sep 17 00:00:00 2001 From: Alex Cunha Date: Tue, 12 Nov 2019 10:16:08 -0600 Subject: [PATCH 09/10] Remove locustfile.py --- locustfile.py | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 locustfile.py diff --git a/locustfile.py b/locustfile.py deleted file mode 100644 index adfbe3cf41..0000000000 --- a/locustfile.py +++ /dev/null @@ -1,11 +0,0 @@ -from locust import HttpLocust, TaskSet, task - -class UserBehavior(TaskSet): - @task(1) - def index(l): - l.client.get("/bundle/") - -class WebsiteUser(HttpLocust): - task_set = UserBehavior - min_wait = 5000 - max_wait = 9000 From 42fc692ae55cd196587adc11ffdd7ce061770859 Mon Sep 17 00:00:00 2001 From: Alex Cunha Date: Tue, 12 Nov 2019 10:25:40 -0600 Subject: [PATCH 10/10] Renamed variables and methods ending _fps to _fail_per_sec --- locust/static/locust.js | 2 +- locust/stats.py | 10 +++++----- locust/templates/index.html | 4 ++-- locust/test/test_stats.py | 8 ++++---- locust/web.py | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/locust/static/locust.js b/locust/static/locust.js index 8cbb6ffab0..a2bac46281 100644 --- a/locust/static/locust.js +++ b/locust/static/locust.js @@ -159,7 +159,7 @@ function updateStats() { // get total stats row var total = report.stats[report.stats.length-1]; // update charts - rpsChart.addValue([total.current_rps, total.current_fps]); + rpsChart.addValue([total.current_rps, total.current_fail_per_sec]); responseTimeChart.addValue([report.current_response_time_percentile_50, report.current_response_time_percentile_95]); usersChart.addValue([report.user_count]); } diff --git a/locust/stats.py b/locust/stats.py index f25a9ffab9..c3aa494cb3 100644 --- a/locust/stats.py +++ b/locust/stats.py @@ -337,7 +337,7 @@ def current_rps(self): return avg(reqs) @property - def current_fps(self): + def current_fail_per_sec(self): if self.stats.last_request_timestamp is None: return 0 slice_start_time = max(self.stats.last_request_timestamp - 12, int(self.stats.start_time or 0)) @@ -447,7 +447,7 @@ def __str__(self): self.max_response_time, self.median_response_time or 0, self.current_rps or 0, - self.current_fps or 0 + self.current_fail_per_sec or 0 ) def get_response_time_percentile(self, percent): @@ -659,13 +659,13 @@ def print_stats(stats): console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7s %12s %7s %7s %7s | %7s %7s %7s") % ('Name', '# reqs', '# fails', 'Avg', 'Min', 'Max', 'Median', 'req/s', 'failures/s')) console_logger.info("-" * (80 + STATS_NAME_WIDTH)) total_rps = 0 - total_fps = 0 + total_fail_per_sec = 0 total_reqs = 0 total_failures = 0 for key in sorted(six.iterkeys(stats)): r = stats[key] total_rps += r.current_rps - total_fps += r.current_fps + total_fail_per_sec += r.current_fail_per_sec total_reqs += r.num_requests total_failures += r.num_failures console_logger.info(r) @@ -676,7 +676,7 @@ def print_stats(stats): except ZeroDivisionError: fail_percent = 0 - console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %42.2f %7.2f") % ('Aggregated', total_reqs, "%d(%.2f%%)" % (total_failures, fail_percent), total_rps, total_fps)) + console_logger.info((" %-" + str(STATS_NAME_WIDTH) + "s %7d %12s %42.2f %7.2f") % ('Aggregated', total_reqs, "%d(%.2f%%)" % (total_failures, fail_percent), total_rps, total_fail_per_sec)) console_logger.info("") def print_percentile_stats(stats): diff --git a/locust/templates/index.html b/locust/templates/index.html index c3b5a85473..a19bfa68ff 100644 --- a/locust/templates/index.html +++ b/locust/templates/index.html @@ -121,7 +121,7 @@

Change the locust count

Max (ms) Average size (bytes) Current RPS - Current Failures/s + Current Failures/s @@ -239,7 +239,7 @@

Version <%= this.max_response_time %> <%= Math.round(this.avg_content_length) %> <%= Math.round(this.current_rps*100)/100 %> - <%= Math.round(this.current_fps*100)/100 %> + <%= Math.round(this.current_fail_per_sec*100)/100 %> <% alternate = !alternate; %> ]]> diff --git a/locust/test/test_stats.py b/locust/test/test_stats.py index ebcdcd1415..ae6af80103 100644 --- a/locust/test/test_stats.py +++ b/locust/test/test_stats.py @@ -63,15 +63,15 @@ def test_current_rps(self): self.stats.total.last_request_timestamp = int(time.time()) + 25 self.assertEqual(self.s.current_rps, 0) - def test_current_fps(self): + def test_current_fail_per_sec(self): self.stats.total.last_request_timestamp = int(time.time()) + 4 - self.assertEqual(self.s.current_fps, 1.5) + self.assertEqual(self.s.current_fail_per_sec, 1.5) self.stats.total.last_request_timestamp = int(time.time()) + 12 - self.assertEqual(self.s.current_fps, 0.3) + self.assertEqual(self.s.current_fail_per_sec, 0.3) self.stats.total.last_request_timestamp = int(time.time()) + 25 - self.assertEqual(self.s.current_fps, 0) + self.assertEqual(self.s.current_fail_per_sec, 0) def test_num_reqs_fails(self): self.assertEqual(self.s.num_requests, 9) diff --git a/locust/web.py b/locust/web.py index 348e6b849e..00888ffc2a 100644 --- a/locust/web.py +++ b/locust/web.py @@ -134,7 +134,7 @@ def request_stats(): "min_response_time": 0 if s.min_response_time is None else proper_round(s.min_response_time), "max_response_time": proper_round(s.max_response_time), "current_rps": s.current_rps, - "current_fps": s.current_fps, + "current_fail_per_sec": s.current_fail_per_sec, "median_response_time": s.median_response_time, "ninetieth_response_time": s.get_response_time_percentile(0.9), "avg_content_length": s.avg_content_length,