Skip to content

Commit

Permalink
print_stats table width fix for locustio#2084
Browse files Browse the repository at this point in the history
  • Loading branch information
mgor committed May 4, 2022
1 parent 63e2c7d commit 190c35d
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 22 deletions.
30 changes: 18 additions & 12 deletions locust/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,11 @@ def to_string(self, current=True):
rps = self.total_rps
fail_per_sec = self.total_fail_per_sec
return (
" %-"
"%-"
+ str(STATS_TYPE_WIDTH)
+ "s %-"
+ str(STATS_NAME_WIDTH)
+ "s %7d %12s | %7d %7d %7d %7d | %7.2f %11.2f"
+ str(STATS_NAME_WIDTH - STATS_TYPE_WIDTH)
+ "s %7d %12s | %7d %7d %7d %7d | %7.2f %11.2f"
) % (
(self.method and self.method + " " or ""),
self.name,
Expand Down Expand Up @@ -602,7 +602,7 @@ def percentile(self):
if not self.num_requests:
raise ValueError("Can't calculate percentile on url with no successful requests")

tpl = f" %-{str(STATS_TYPE_WIDTH)}s %-{str(STATS_NAME_WIDTH)}s %8d {' '.join(['%6d'] * len(PERCENTILES_TO_REPORT))}"
tpl = f"%-{str(STATS_TYPE_WIDTH)}s %-{str(STATS_NAME_WIDTH)}s %8d {' '.join(['%6d'] * len(PERCENTILES_TO_REPORT))}"

return tpl % (
(self.method or "", self.name)
Expand Down Expand Up @@ -730,10 +730,16 @@ def on_worker_report(client_id, data):

def print_stats(stats, current=True):
console_logger.info(
(" %-" + str(STATS_TYPE_WIDTH) + "s %-" + str(STATS_NAME_WIDTH) + "s %7s %12s | %7s %7s %7s %7s | %7s %11s")
(
"%-"
+ str(STATS_TYPE_WIDTH)
+ "s %-"
+ str(STATS_NAME_WIDTH - STATS_TYPE_WIDTH)
+ "s %7s %12s | %7s %7s %7s %7s | %7s %11s"
)
% ("Type", "Name", "# reqs", "# fails", "Avg", "Min", "Max", "Median", "req/s", "failures/s")
)
separator = f'{"-" * STATS_TYPE_WIDTH}|{"-" * STATS_NAME_WIDTH}|{"-" * 8}|{"-" * (13 + 1)}|{"-" * 8}|{"-" * 7}|{"-" * 7}|{"-" * (7 + 2)}|{"-" * 8}|{"-" * 12}|'
separator = f'{"-" * STATS_TYPE_WIDTH}|{"-" * (STATS_NAME_WIDTH - STATS_TYPE_WIDTH)}|{"-" * 7}|{"-" * 13}|{"-" * 8}|{"-" * 7}|{"-" * 7}|{"-" * 8}|{"-" * 8}|{"-" * 11}'
console_logger.info(separator)
for key in sorted(stats.entries.keys()):
r = stats.entries[key]
Expand All @@ -748,14 +754,14 @@ def print_percentile_stats(stats):
headers = ("Type", "Name") + tuple(get_readable_percentiles(PERCENTILES_TO_REPORT)) + ("# reqs",)
console_logger.info(
(
f" %-{str(STATS_TYPE_WIDTH)}s %-{str(STATS_NAME_WIDTH)}s %8s "
f"%-{str(STATS_TYPE_WIDTH)}s %-{str(STATS_NAME_WIDTH)}s %8s "
f"{' '.join(['%6s'] * len(PERCENTILES_TO_REPORT))}"
)
% headers
)
separator = (
f'{"-" * STATS_TYPE_WIDTH}|{"-" * STATS_NAME_WIDTH}|{"-" * 9}|{("-" * 6 + "|") * len(PERCENTILES_TO_REPORT)}'
)
f'{"-" * STATS_TYPE_WIDTH}|{"-" * STATS_NAME_WIDTH}|{"-" * 8}|{("-" * 6 + "|") * len(PERCENTILES_TO_REPORT)}'
)[:-1]
console_logger.info(separator)
for key in sorted(stats.entries.keys()):
r = stats.entries[key]
Expand All @@ -772,11 +778,11 @@ def print_error_report(stats):
if not len(stats.errors):
return
console_logger.info("Error report")
console_logger.info(" %-18s %-100s" % ("# occurrences", "Error"))
separator = f'{"-" * 18}|{"-" * ((80 + STATS_NAME_WIDTH) - 19)}|'
console_logger.info("%-18s %-100s" % ("# occurrences", "Error"))
separator = f'{"-" * 18}|{"-" * ((80 + STATS_NAME_WIDTH) - 19)}'
console_logger.info(separator)
for error in stats.errors.values():
console_logger.info(" %-18i %-100s" % (error.occurrences, error.to_name()))
console_logger.info("%-18i %-100s" % (error.occurrences, error.to_name()))
console_logger.info(separator)
console_logger.info("")

Expand Down
40 changes: 30 additions & 10 deletions locust/test/test_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@
from locust import HttpUser, TaskSet, task, User, constant, __version__
from locust.env import Environment
from locust.rpc.protocol import Message
from locust.stats import CachedResponseTimes, RequestStats, StatsEntry, diff_response_time_dicts, PERCENTILES_TO_REPORT
from locust.stats import (
CachedResponseTimes,
RequestStats,
StatsEntry,
diff_response_time_dicts,
PERCENTILES_TO_REPORT,
STATS_NAME_WIDTH,
STATS_TYPE_WIDTH,
)
from locust.stats import StatsCSVFileWriter
from locust.stats import stats_history
from locust.test.testcases import LocustTestCase
Expand Down Expand Up @@ -309,14 +317,26 @@ def setUp(self):

self.stats = RequestStats()
for i in range(100):
self.stats.log_request("GET", "test_entry", i, 2000 + i)
if i % 5 == 0:
self.stats.log_error("GET", "test_entry", RuntimeError("error"))
for method, name, freq in [
(
"GET",
"test_entry",
5,
),
(
"DELETE",
"test" * int((STATS_NAME_WIDTH - STATS_TYPE_WIDTH) / len("test")),
3,
),
]:
self.stats.log_request(method, name, i, 2000 + i)
if i % freq == 0:
self.stats.log_error(method, name, RuntimeError(f"{method} error"))

def test_print_percentile_stats(self):
locust.stats.print_percentile_stats(self.stats)
info = self.mocked_log.info
self.assertEqual(7, len(info))
self.assertEqual(8, len(info))
self.assertEqual("Response time percentiles (approximated)", info[0])
# check that headline contains same number of column as the value rows
headlines = info[1].replace("# reqs", "#reqs").split()
Expand All @@ -327,12 +347,12 @@ def test_print_percentile_stats(self):
def test_print_stats(self):
locust.stats.print_stats(self.stats)
info = self.mocked_log.info
self.assertEqual(6, len(info))
self.assertEqual(7, len(info))

headlines = info[0].replace("# ", "#").split()

# check number of columns in separator, which will end with a pipe as well
self.assertEqual(len(headlines), len(info[1].split("|")) + 1)
# check number of columns in separator
self.assertEqual(len(headlines), len(info[1].split("|")) + 2)
# check entry row
self.assertEqual(len(headlines), len(info[2].split()))
# check aggregated row, which is missing value in "type"-column
Expand All @@ -343,12 +363,12 @@ def test_print_stats(self):
def test_print_error_report(self):
locust.stats.print_error_report(self.stats)
info = self.mocked_log.info
self.assertEqual(6, len(info))
self.assertEqual(7, len(info))
self.assertEqual("Error report", info[0])

headlines = info[1].replace("# ", "#").split()
# check number of columns in headlines vs table ascii separator
self.assertEqual(len(headlines), len(info[2].split("|")) - 1)
self.assertEqual(len(headlines), len(info[2].split("|")))
# table ascii seprators
self.assertEqual(info[2], info[-2])

Expand Down

0 comments on commit 190c35d

Please sign in to comment.