locust 2.18.1.dev10__py3-none-any.whl → 2.18.1.dev16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of locust might be problematic. Click here for more details.
- locust/_version.py +2 -2
- locust/log.py +15 -5
- locust/test/test_web.py +15 -1
- locust/web.py +20 -0
- locust/webui/dist/assets/index-b46361c2.js +236 -0
- locust/webui/dist/index.html +1 -1
- {locust-2.18.1.dev10.dist-info → locust-2.18.1.dev16.dist-info}/METADATA +1 -1
- {locust-2.18.1.dev10.dist-info → locust-2.18.1.dev16.dist-info}/RECORD +12 -11
- {locust-2.18.1.dev10.dist-info → locust-2.18.1.dev16.dist-info}/LICENSE +0 -0
- {locust-2.18.1.dev10.dist-info → locust-2.18.1.dev16.dist-info}/WHEEL +0 -0
- {locust-2.18.1.dev10.dist-info → locust-2.18.1.dev16.dist-info}/entry_points.txt +0 -0
- {locust-2.18.1.dev10.dist-info → locust-2.18.1.dev16.dist-info}/top_level.txt +0 -0
locust/_version.py
CHANGED
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '2.18.1.
|
16
|
-
__version_tuple__ = version_tuple = (2, 18, 1, '
|
15
|
+
__version__ = version = '2.18.1.dev16'
|
16
|
+
__version_tuple__ = version_tuple = (2, 18, 1, 'dev16')
|
locust/log.py
CHANGED
@@ -9,6 +9,15 @@ HOSTNAME = socket.gethostname()
|
|
9
9
|
unhandled_greenlet_exception = False
|
10
10
|
|
11
11
|
|
12
|
+
class LogReader(logging.Handler):
|
13
|
+
def __init__(self):
|
14
|
+
super().__init__()
|
15
|
+
self.logs = []
|
16
|
+
|
17
|
+
def emit(self, record):
|
18
|
+
self.logs.append(self.format(record))
|
19
|
+
|
20
|
+
|
12
21
|
def setup_logging(loglevel, logfile=None):
|
13
22
|
loglevel = loglevel.upper()
|
14
23
|
|
@@ -32,21 +41,22 @@ def setup_logging(loglevel, logfile=None):
|
|
32
41
|
"class": "logging.StreamHandler",
|
33
42
|
"formatter": "plain",
|
34
43
|
},
|
44
|
+
"log_reader": {"class": "locust.log.LogReader", "formatter": "default"},
|
35
45
|
},
|
36
46
|
"loggers": {
|
37
47
|
"locust": {
|
38
|
-
"handlers": ["console"],
|
48
|
+
"handlers": ["console", "log_reader"],
|
39
49
|
"level": loglevel,
|
40
50
|
"propagate": False,
|
41
51
|
},
|
42
52
|
"locust.stats_logger": {
|
43
|
-
"handlers": ["console_plain"],
|
53
|
+
"handlers": ["console_plain", "log_reader"],
|
44
54
|
"level": "INFO",
|
45
55
|
"propagate": False,
|
46
56
|
},
|
47
57
|
},
|
48
58
|
"root": {
|
49
|
-
"handlers": ["console"],
|
59
|
+
"handlers": ["console", "log_reader"],
|
50
60
|
"level": loglevel,
|
51
61
|
},
|
52
62
|
}
|
@@ -58,8 +68,8 @@ def setup_logging(loglevel, logfile=None):
|
|
58
68
|
"filename": logfile,
|
59
69
|
"formatter": "default",
|
60
70
|
}
|
61
|
-
LOGGING_CONFIG["loggers"]["locust"]["handlers"] = ["file"]
|
62
|
-
LOGGING_CONFIG["root"]["handlers"] = ["file"]
|
71
|
+
LOGGING_CONFIG["loggers"]["locust"]["handlers"] = ["file", "log_reader"]
|
72
|
+
LOGGING_CONFIG["root"]["handlers"] = ["file", "log_reader"]
|
63
73
|
|
64
74
|
logging.config.dictConfig(LOGGING_CONFIG)
|
65
75
|
|
locust/test/test_web.py
CHANGED
@@ -5,13 +5,13 @@ import os
|
|
5
5
|
import re
|
6
6
|
import textwrap
|
7
7
|
import traceback
|
8
|
+
import logging
|
8
9
|
from io import StringIO
|
9
10
|
from tempfile import NamedTemporaryFile, TemporaryDirectory
|
10
11
|
|
11
12
|
import gevent
|
12
13
|
import requests
|
13
14
|
from pyquery import PyQuery as pq
|
14
|
-
|
15
15
|
import locust
|
16
16
|
from locust import constant, LoadTestShape
|
17
17
|
from locust.argument_parser import get_parser, parse_options
|
@@ -21,6 +21,7 @@ from locust.runners import Runner
|
|
21
21
|
from locust import stats
|
22
22
|
from locust.stats import StatsCSVFileWriter
|
23
23
|
from locust.web import WebUI
|
24
|
+
from locust.log import LogReader
|
24
25
|
|
25
26
|
from .mock_locustfile import mock_locustfile
|
26
27
|
from .testcases import LocustTestCase
|
@@ -1013,6 +1014,19 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
|
|
1013
1014
|
self.assertIn("Script: <span>locust.py</span>", str(d))
|
1014
1015
|
self.assertIn("Target Host: <span>http://localhost</span>", str(d))
|
1015
1016
|
|
1017
|
+
def test_logs(self):
|
1018
|
+
log_handler = LogReader()
|
1019
|
+
log_handler.name = "log_reader"
|
1020
|
+
log_handler.setLevel(logging.INFO)
|
1021
|
+
logger = logging.getLogger("root")
|
1022
|
+
logger.addHandler(log_handler)
|
1023
|
+
log_line = "some log info"
|
1024
|
+
logger.info(log_line)
|
1025
|
+
|
1026
|
+
response = requests.get("http://127.0.0.1:%i/logs" % self.web_port)
|
1027
|
+
|
1028
|
+
self.assertIn(log_line, response.json().get("logs"))
|
1029
|
+
|
1016
1030
|
|
1017
1031
|
class TestWebUIAuth(LocustTestCase):
|
1018
1032
|
def setUp(self):
|
locust/web.py
CHANGED
@@ -136,6 +136,12 @@ class WebUI:
|
|
136
136
|
if not delayed_start:
|
137
137
|
self.start()
|
138
138
|
|
139
|
+
@app.errorhandler(Exception)
|
140
|
+
def handle_exception(error):
|
141
|
+
error_message = str(error)
|
142
|
+
logger.log(logging.CRITICAL, error_message)
|
143
|
+
return make_response(error_message, 500)
|
144
|
+
|
139
145
|
@app.route("/assets/<path:path>")
|
140
146
|
def send_assets(path):
|
141
147
|
webui_build_path = self.webui_build_path
|
@@ -478,6 +484,20 @@ class WebUI:
|
|
478
484
|
}
|
479
485
|
return task_data
|
480
486
|
|
487
|
+
@app.route("/logs")
|
488
|
+
@self.auth_required_if_enabled
|
489
|
+
def logs():
|
490
|
+
log_reader_handler = [
|
491
|
+
handler for handler in logging.getLogger("root").handlers if handler.name == "log_reader"
|
492
|
+
]
|
493
|
+
|
494
|
+
if log_reader_handler:
|
495
|
+
logs = log_reader_handler[0].logs
|
496
|
+
else:
|
497
|
+
logs = []
|
498
|
+
|
499
|
+
return jsonify({"logs": logs})
|
500
|
+
|
481
501
|
def start(self):
|
482
502
|
self.greenlet = gevent.spawn(self.start_server)
|
483
503
|
self.greenlet.link_exception(greenlet_exception_handler)
|