We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
We should check limits (ulimit) and warn if they are too low
Occasionally people file tickets/SO issues that seem to relate to this:

https://github.com/locustio/locust/issues/496

https://stackoverflow.com/questions/61633170/locust-error-nodename-nor-servname-provided-or-not-known/61651507?noredirect=1#comment109058148_61651507

We could add something like this:
```
if resource.getrlimit(resource.RLIMIT_NOFILE)[0] < 10000:
    logger.warning("System open file limit setting is not high enough for load testing. See https://docs.locust.io/en/stable/installation.html#increasing-maximum-number-of-open-files-limit for more info.")
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `locust/main.py`
Content:
```
1 import inspect
2 import logging
3 import os
4 import importlib
5 import signal
6 import socket
7 import sys
8 import time
9 
10 import gevent
11 
12 import locust
13 
14 from . import log
15 from .argument_parser import parse_locustfile_option, parse_options
16 from .env import Environment
17 from .log import setup_logging, greenlet_exception_logger
18 from .stats import (print_error_report, print_percentile_stats, print_stats,
19                     stats_printer, stats_writer, write_csv_files)
20 from .user import User
21 from .user.inspectuser import get_task_ratio_dict, print_task_ratio
22 from .util.timespan import parse_timespan
23 from .exception import AuthCredentialsError
24 
25 version = locust.__version__
26 
27 
28 def is_user_class(item):
29     """
30     Check if a variable is a runnable (non-abstract) User class
31     """
32     return bool(
33         inspect.isclass(item)
34         and issubclass(item, User)
35         and item.abstract == False
36     )
37 
38 
39 def load_locustfile(path):
40     """
41     Import given locustfile path and return (docstring, callables).
42 
43     Specifically, the locustfile's ``__doc__`` attribute (a string) and a
44     dictionary of ``{'name': callable}`` containing all callables which pass
45     the "is a Locust" test.
46     """
47 
48     def __import_locustfile__(filename, path):
49         """
50         Loads the locust file as a module, similar to performing `import`
51         """
52         source = importlib.machinery.SourceFileLoader(os.path.splitext(locustfile)[0], path)
53         return  source.load_module()
54 
55     # Start with making sure the current working dir is in the sys.path
56     sys.path.insert(0, os.getcwd())
57     # Get directory and locustfile name
58     directory, locustfile = os.path.split(path)
59     # If the directory isn't in the PYTHONPATH, add it so our import will work
60     added_to_path = False
61     index = None
62     if directory not in sys.path:
63         sys.path.insert(0, directory)
64         added_to_path = True
65     # If the directory IS in the PYTHONPATH, move it to the front temporarily,
66     # otherwise other locustfiles -- like Locusts's own -- may scoop the intended
67     # one.
68     else:
69         i = sys.path.index(directory)
70         if i != 0:
71             # Store index for later restoration
72             index = i
73             # Add to front, then remove from original position
74             sys.path.insert(0, directory)
75             del sys.path[i + 1]
76     # Perform the import
77     imported = __import_locustfile__(locustfile, path)
78     # Remove directory from path if we added it ourselves (just to be neat)
79     if added_to_path:
80         del sys.path[0]
81     # Put back in original index if we moved it
82     if index is not None:
83         sys.path.insert(index + 1, directory)
84         del sys.path[0]
85     # Return our two-tuple
86     user_classes = {name:value for name, value in vars(imported).items() if is_user_class(value)}
87     return imported.__doc__, user_classes
88 
89 
90 def create_environment(user_classes, options, events=None):
91     """
92     Create an Environment instance from options
93     """
94     return Environment(
95         user_classes=user_classes,
96         tags=options.tags,
97         exclude_tags=options.exclude_tags,
98         events=events,
99         host=options.host,
100         reset_stats=options.reset_stats,
101         step_load=options.step_load,
102         stop_timeout=options.stop_timeout,
103         parsed_options=options
104     )
105 
106 
107 def main():
108     # find specified locustfile and make sure it exists, using a very simplified
109     # command line parser that is only used to parse the -f option
110     locustfile = parse_locustfile_option()
111     
112     # import the locustfile
113     docstring, user_classes = load_locustfile(locustfile)
114     
115     # parse all command line options
116     options = parse_options()
117 
118     if options.slave or options.expect_slaves:
119         sys.stderr.write("[DEPRECATED] Usage of slave has been deprecated, use --worker or --expect-workers\n")
120         sys.exit(1)
121     
122     # setup logging
123     if not options.skip_log_setup:
124         if options.loglevel.upper() in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
125             setup_logging(options.loglevel, options.logfile)
126         else:
127             sys.stderr.write("Invalid --loglevel. Valid values are: DEBUG/INFO/WARNING/ERROR/CRITICAL\n")
128             sys.exit(1)
129 
130     logger = logging.getLogger(__name__)
131     greenlet_exception_handler = greenlet_exception_logger(logger)
132 
133     if options.list_commands:
134         print("Available Users:")
135         for name in user_classes:
136             print("    " + name)
137         sys.exit(0)
138 
139     if not user_classes:
140         logger.error("No User class found!")
141         sys.exit(1)
142 
143     # make sure specified User exists
144     if options.user_classes:
145         missing = set(options.user_classes) - set(user_classes.keys())
146         if missing:
147             logger.error("Unknown User(s): %s\n" % (", ".join(missing)))
148             sys.exit(1)
149         else:
150             names = set(options.user_classes) & set(user_classes.keys())
151             user_classes = [user_classes[n] for n in names]
152     else:
153         # list() call is needed to consume the dict_view object in Python 3
154         user_classes = list(user_classes.values())
155     
156     # create locust Environment
157     environment = create_environment(user_classes, options, events=locust.events)
158     
159     if options.show_task_ratio:
160         print("\n Task ratio per User class")
161         print( "-" * 80)
162         print_task_ratio(user_classes)
163         print("\n Total task ratio")
164         print("-" * 80)
165         print_task_ratio(user_classes, total=True)
166         sys.exit(0)
167     if options.show_task_ratio_json:
168         from json import dumps
169         task_data = {
170             "per_class": get_task_ratio_dict(user_classes),
171             "total": get_task_ratio_dict(user_classes, total=True)
172         }
173         print(dumps(task_data))
174         sys.exit(0)
175 
176     if options.step_time:
177         if not options.step_load:
178             logger.error("The --step-time argument can only be used together with --step-load")
179             sys.exit(1)
180         if options.worker:
181             logger.error("--step-time should be specified on the master node, and not on worker nodes")
182             sys.exit(1)
183         try:
184             options.step_time = parse_timespan(options.step_time)
185         except ValueError:
186             logger.error("Valid --step-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.")
187             sys.exit(1)
188     
189     if options.master:
190         runner = environment.create_master_runner(
191             master_bind_host=options.master_bind_host, 
192             master_bind_port=options.master_bind_port,
193         )
194     elif options.worker:
195         try:
196             runner = environment.create_worker_runner(options.master_host, options.master_port)
197         except socket.error as e:
198             logger.error("Failed to connect to the Locust master: %s", e)
199             sys.exit(-1)
200     else:
201         runner = environment.create_local_runner()
202     
203     # main_greenlet is pointing to runners.greenlet by default, it will point the web greenlet later if in web mode
204     main_greenlet = runner.greenlet
205     
206     if options.run_time:
207         if not options.headless:
208             logger.error("The --run-time argument can only be used together with --headless")
209             sys.exit(1)
210         if options.worker:
211             logger.error("--run-time should be specified on the master node, and not on worker nodes")
212             sys.exit(1)
213         try:
214             options.run_time = parse_timespan(options.run_time)
215         except ValueError:
216             logger.error("Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.")
217             sys.exit(1)
218         def spawn_run_time_limit_greenlet():
219             logger.info("Run time limit set to %s seconds" % options.run_time)
220             def timelimit_stop():
221                 logger.info("Time limit reached. Stopping Locust.")
222                 runner.quit()
223             gevent.spawn_later(options.run_time, timelimit_stop).link_exception(greenlet_exception_handler)
224     
225     # start Web UI
226     if not options.headless and not options.worker:
227         # spawn web greenlet
228         protocol = "https" if options.tls_cert and options.tls_key else "http"
229         logger.info("Starting web monitor at %s://%s:%s" % (protocol, options.web_host, options.web_port))
230         try:
231             if options.web_host == "*":
232                 # special check for "*" so that we're consistent with --master-bind-host
233                 web_host = ''
234             else:
235                 web_host = options.web_host
236             web_ui = environment.create_web_ui(
237                 host=web_host, 
238                 port=options.web_port, 
239                 auth_credentials=options.web_auth, 
240                 tls_cert=options.tls_cert, 
241                 tls_key=options.tls_key,
242             )
243         except AuthCredentialsError:
244             logger.error("Credentials supplied with --web-auth should have the format: username:password")
245             sys.exit(1)
246         else:
247             main_greenlet = web_ui.greenlet
248     else:
249         web_ui = None
250     
251     # Fire locust init event which can be used by end-users' code to run setup code that
252     # need access to the Environment, Runner or WebUI
253     environment.events.init.fire(environment=environment, runner=runner, web_ui=web_ui)    
254     
255     if options.headless:
256         # headless mode
257         if options.master:
258             # wait for worker nodes to connect
259             while len(runner.clients.ready) < options.expect_workers:
260                 logging.info("Waiting for workers to be ready, %s of %s connected",
261                              len(runner.clients.ready), options.expect_workers)
262                 time.sleep(1)
263         if not options.worker:
264             # apply headless mode defaults
265             if options.num_users is None:
266                 options.num_users = 1
267             if options.hatch_rate is None:
268                 options.hatch_rate = 1
269             if options.step_users is None:
270                 options.step_users = 1
271 
272             # start the test
273             if options.step_time:
274                 runner.start_stepload(options.num_users, options.hatch_rate, options.step_users, options.step_time)
275             else:
276                 runner.start(options.num_users, options.hatch_rate)
277     
278     if options.run_time:
279         spawn_run_time_limit_greenlet()
280 
281     stats_printer_greenlet = None
282     if not options.only_summary and (options.print_stats or (options.headless and not options.worker)):
283         # spawn stats printing greenlet
284         stats_printer_greenlet = gevent.spawn(stats_printer(runner.stats))
285         stats_printer_greenlet.link_exception(greenlet_exception_handler)
286 
287     if options.csv_prefix:
288         gevent.spawn(stats_writer, environment, options.csv_prefix, full_history=options.stats_history_enabled).link_exception(greenlet_exception_handler)
289 
290     
291     def shutdown(code=0):
292         """
293         Shut down locust by firing quitting event, printing/writing stats and exiting
294         """
295         logger.info("Shutting down (exit code %s), bye." % code)
296         if stats_printer_greenlet is not None:
297             stats_printer_greenlet.kill(block=False)
298         logger.info("Cleaning up runner...")
299         if runner is not None:
300             runner.quit()
301         logger.info("Running teardowns...")
302         environment.events.quitting.fire(reverse=True)
303         print_stats(runner.stats, current=False)
304         print_percentile_stats(runner.stats)
305         if options.csv_prefix:
306             write_csv_files(environment, options.csv_prefix, full_history=options.stats_history_enabled)
307         print_error_report(runner.stats)
308         sys.exit(code)
309     
310     # install SIGTERM handler
311     def sig_term_handler():
312         logger.info("Got SIGTERM signal")
313         shutdown(0)
314     gevent.signal_handler(signal.SIGTERM, sig_term_handler)
315     
316     try:
317         logger.info("Starting Locust %s" % version)
318         main_greenlet.join()
319         code = 0
320         if log.unhandled_greenlet_exception:
321             code = 2
322         elif len(runner.errors) or len(runner.exceptions):
323             code = options.exit_code_on_error
324         shutdown(code=code)
325     except KeyboardInterrupt as e:
326         shutdown(0)
327
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/locust/main.py b/locust/main.py
--- a/locust/main.py
+++ b/locust/main.py
@@ -6,6 +6,7 @@
 import socket
 import sys
 import time
+import resource 
 
 import gevent
 
@@ -153,6 +154,14 @@
         # list() call is needed to consume the dict_view object in Python 3
         user_classes = list(user_classes.values())
     
+    try:
+        if resource.getrlimit(resource.RLIMIT_NOFILE)[0] < 10000:
+            # Increasing the limit to 10000 within a running process should work on at least MacOS.
+            # It does not work on all OS:es, but we should be no worse off for trying.
+            resource.setrlimit(resource.RLIMIT_NOFILE, [10000, resource.RLIM_INFINITY])
+    except:
+        logger.warning("System open file limit setting is not high enough for load testing, and the OS wouldnt allow locust to increase it by itself. See https://docs.locust.io/en/stable/installation.html#increasing-maximum-number-of-open-files-limit for more info.")
+
     # create locust Environment
     environment = create_environment(user_classes, options, events=locust.events)

{"golden_diff": "diff --git a/locust/main.py b/locust/main.py\n--- a/locust/main.py\n+++ b/locust/main.py\n@@ -6,6 +6,7 @@\n import socket\n import sys\n import time\n+import resource \n \n import gevent\n \n@@ -153,6 +154,14 @@\n         # list() call is needed to consume the dict_view object in Python 3\n         user_classes = list(user_classes.values())\n     \n+    try:\n+        if resource.getrlimit(resource.RLIMIT_NOFILE)[0] < 10000:\n+            # Increasing the limit to 10000 within a running process should work on at least MacOS.\n+            # It does not work on all OS:es, but we should be no worse off for trying.\n+            resource.setrlimit(resource.RLIMIT_NOFILE, [10000, resource.RLIM_INFINITY])\n+    except:\n+        logger.warning(\"System open file limit setting is not high enough for load testing, and the OS wouldnt allow locust to increase it by itself. See https://docs.locust.io/en/stable/installation.html#increasing-maximum-number-of-open-files-limit for more info.\")\n+\n     # create locust Environment\n     environment = create_environment(user_classes, options, events=locust.events)\n", "issue": "We should check limits (ulimit) and warn if they are too low\nOccasionally people file tickets/SO issues that seem to relate to this:\r\n\r\nhttps://github.com/locustio/locust/issues/496\r\n\r\nhttps://stackoverflow.com/questions/61633170/locust-error-nodename-nor-servname-provided-or-not-known/61651507?noredirect=1#comment109058148_61651507\r\n\r\nWe could add something like this:\r\n```\r\nif resource.getrlimit(resource.RLIMIT_NOFILE)[0] < 10000:\r\n    logger.warning(\"System open file limit setting is not high enough for load testing. See https://docs.locust.io/en/stable/installation.html#increasing-maximum-number-of-open-files-limit for more info.\")\r\n```\n", "before_files": [{"content": "import inspect\nimport logging\nimport os\nimport importlib\nimport signal\nimport socket\nimport sys\nimport time\n\nimport gevent\n\nimport locust\n\nfrom . import log\nfrom .argument_parser import parse_locustfile_option, parse_options\nfrom .env import Environment\nfrom .log import setup_logging, greenlet_exception_logger\nfrom .stats import (print_error_report, print_percentile_stats, print_stats,\n                    stats_printer, stats_writer, write_csv_files)\nfrom .user import User\nfrom .user.inspectuser import get_task_ratio_dict, print_task_ratio\nfrom .util.timespan import parse_timespan\nfrom .exception import AuthCredentialsError\n\nversion = locust.__version__\n\n\ndef is_user_class(item):\n    \"\"\"\n    Check if a variable is a runnable (non-abstract) User class\n    \"\"\"\n    return bool(\n        inspect.isclass(item)\n        and issubclass(item, User)\n        and item.abstract == False\n    )\n\n\ndef load_locustfile(path):\n    \"\"\"\n    Import given locustfile path and return (docstring, callables).\n\n    Specifically, the locustfile's ``__doc__`` attribute (a string) and a\n    dictionary of ``{'name': callable}`` containing all callables which pass\n    the \"is a Locust\" test.\n    \"\"\"\n\n    def __import_locustfile__(filename, path):\n        \"\"\"\n        Loads the locust file as a module, similar to performing `import`\n        \"\"\"\n        source = importlib.machinery.SourceFileLoader(os.path.splitext(locustfile)[0], path)\n        return  source.load_module()\n\n    # Start with making sure the current working dir is in the sys.path\n    sys.path.insert(0, os.getcwd())\n    # Get directory and locustfile name\n    directory, locustfile = os.path.split(path)\n    # If the directory isn't in the PYTHONPATH, add it so our import will work\n    added_to_path = False\n    index = None\n    if directory not in sys.path:\n        sys.path.insert(0, directory)\n        added_to_path = True\n    # If the directory IS in the PYTHONPATH, move it to the front temporarily,\n    # otherwise other locustfiles -- like Locusts's own -- may scoop the intended\n    # one.\n    else:\n        i = sys.path.index(directory)\n        if i != 0:\n            # Store index for later restoration\n            index = i\n            # Add to front, then remove from original position\n            sys.path.insert(0, directory)\n            del sys.path[i + 1]\n    # Perform the import\n    imported = __import_locustfile__(locustfile, path)\n    # Remove directory from path if we added it ourselves (just to be neat)\n    if added_to_path:\n        del sys.path[0]\n    # Put back in original index if we moved it\n    if index is not None:\n        sys.path.insert(index + 1, directory)\n        del sys.path[0]\n    # Return our two-tuple\n    user_classes = {name:value for name, value in vars(imported).items() if is_user_class(value)}\n    return imported.__doc__, user_classes\n\n\ndef create_environment(user_classes, options, events=None):\n    \"\"\"\n    Create an Environment instance from options\n    \"\"\"\n    return Environment(\n        user_classes=user_classes,\n        tags=options.tags,\n        exclude_tags=options.exclude_tags,\n        events=events,\n        host=options.host,\n        reset_stats=options.reset_stats,\n        step_load=options.step_load,\n        stop_timeout=options.stop_timeout,\n        parsed_options=options\n    )\n\n\ndef main():\n    # find specified locustfile and make sure it exists, using a very simplified\n    # command line parser that is only used to parse the -f option\n    locustfile = parse_locustfile_option()\n    \n    # import the locustfile\n    docstring, user_classes = load_locustfile(locustfile)\n    \n    # parse all command line options\n    options = parse_options()\n\n    if options.slave or options.expect_slaves:\n        sys.stderr.write(\"[DEPRECATED] Usage of slave has been deprecated, use --worker or --expect-workers\\n\")\n        sys.exit(1)\n    \n    # setup logging\n    if not options.skip_log_setup:\n        if options.loglevel.upper() in [\"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"]:\n            setup_logging(options.loglevel, options.logfile)\n        else:\n            sys.stderr.write(\"Invalid --loglevel. Valid values are: DEBUG/INFO/WARNING/ERROR/CRITICAL\\n\")\n            sys.exit(1)\n\n    logger = logging.getLogger(__name__)\n    greenlet_exception_handler = greenlet_exception_logger(logger)\n\n    if options.list_commands:\n        print(\"Available Users:\")\n        for name in user_classes:\n            print(\"    \" + name)\n        sys.exit(0)\n\n    if not user_classes:\n        logger.error(\"No User class found!\")\n        sys.exit(1)\n\n    # make sure specified User exists\n    if options.user_classes:\n        missing = set(options.user_classes) - set(user_classes.keys())\n        if missing:\n            logger.error(\"Unknown User(s): %s\\n\" % (\", \".join(missing)))\n            sys.exit(1)\n        else:\n            names = set(options.user_classes) & set(user_classes.keys())\n            user_classes = [user_classes[n] for n in names]\n    else:\n        # list() call is needed to consume the dict_view object in Python 3\n        user_classes = list(user_classes.values())\n    \n    # create locust Environment\n    environment = create_environment(user_classes, options, events=locust.events)\n    \n    if options.show_task_ratio:\n        print(\"\\n Task ratio per User class\")\n        print( \"-\" * 80)\n        print_task_ratio(user_classes)\n        print(\"\\n Total task ratio\")\n        print(\"-\" * 80)\n        print_task_ratio(user_classes, total=True)\n        sys.exit(0)\n    if options.show_task_ratio_json:\n        from json import dumps\n        task_data = {\n            \"per_class\": get_task_ratio_dict(user_classes),\n            \"total\": get_task_ratio_dict(user_classes, total=True)\n        }\n        print(dumps(task_data))\n        sys.exit(0)\n\n    if options.step_time:\n        if not options.step_load:\n            logger.error(\"The --step-time argument can only be used together with --step-load\")\n            sys.exit(1)\n        if options.worker:\n            logger.error(\"--step-time should be specified on the master node, and not on worker nodes\")\n            sys.exit(1)\n        try:\n            options.step_time = parse_timespan(options.step_time)\n        except ValueError:\n            logger.error(\"Valid --step-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.\")\n            sys.exit(1)\n    \n    if options.master:\n        runner = environment.create_master_runner(\n            master_bind_host=options.master_bind_host, \n            master_bind_port=options.master_bind_port,\n        )\n    elif options.worker:\n        try:\n            runner = environment.create_worker_runner(options.master_host, options.master_port)\n        except socket.error as e:\n            logger.error(\"Failed to connect to the Locust master: %s\", e)\n            sys.exit(-1)\n    else:\n        runner = environment.create_local_runner()\n    \n    # main_greenlet is pointing to runners.greenlet by default, it will point the web greenlet later if in web mode\n    main_greenlet = runner.greenlet\n    \n    if options.run_time:\n        if not options.headless:\n            logger.error(\"The --run-time argument can only be used together with --headless\")\n            sys.exit(1)\n        if options.worker:\n            logger.error(\"--run-time should be specified on the master node, and not on worker nodes\")\n            sys.exit(1)\n        try:\n            options.run_time = parse_timespan(options.run_time)\n        except ValueError:\n            logger.error(\"Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.\")\n            sys.exit(1)\n        def spawn_run_time_limit_greenlet():\n            logger.info(\"Run time limit set to %s seconds\" % options.run_time)\n            def timelimit_stop():\n                logger.info(\"Time limit reached. Stopping Locust.\")\n                runner.quit()\n            gevent.spawn_later(options.run_time, timelimit_stop).link_exception(greenlet_exception_handler)\n    \n    # start Web UI\n    if not options.headless and not options.worker:\n        # spawn web greenlet\n        protocol = \"https\" if options.tls_cert and options.tls_key else \"http\"\n        logger.info(\"Starting web monitor at %s://%s:%s\" % (protocol, options.web_host, options.web_port))\n        try:\n            if options.web_host == \"*\":\n                # special check for \"*\" so that we're consistent with --master-bind-host\n                web_host = ''\n            else:\n                web_host = options.web_host\n            web_ui = environment.create_web_ui(\n                host=web_host, \n                port=options.web_port, \n                auth_credentials=options.web_auth, \n                tls_cert=options.tls_cert, \n                tls_key=options.tls_key,\n            )\n        except AuthCredentialsError:\n            logger.error(\"Credentials supplied with --web-auth should have the format: username:password\")\n            sys.exit(1)\n        else:\n            main_greenlet = web_ui.greenlet\n    else:\n        web_ui = None\n    \n    # Fire locust init event which can be used by end-users' code to run setup code that\n    # need access to the Environment, Runner or WebUI\n    environment.events.init.fire(environment=environment, runner=runner, web_ui=web_ui)    \n    \n    if options.headless:\n        # headless mode\n        if options.master:\n            # wait for worker nodes to connect\n            while len(runner.clients.ready) < options.expect_workers:\n                logging.info(\"Waiting for workers to be ready, %s of %s connected\",\n                             len(runner.clients.ready), options.expect_workers)\n                time.sleep(1)\n        if not options.worker:\n            # apply headless mode defaults\n            if options.num_users is None:\n                options.num_users = 1\n            if options.hatch_rate is None:\n                options.hatch_rate = 1\n            if options.step_users is None:\n                options.step_users = 1\n\n            # start the test\n            if options.step_time:\n                runner.start_stepload(options.num_users, options.hatch_rate, options.step_users, options.step_time)\n            else:\n                runner.start(options.num_users, options.hatch_rate)\n    \n    if options.run_time:\n        spawn_run_time_limit_greenlet()\n\n    stats_printer_greenlet = None\n    if not options.only_summary and (options.print_stats or (options.headless and not options.worker)):\n        # spawn stats printing greenlet\n        stats_printer_greenlet = gevent.spawn(stats_printer(runner.stats))\n        stats_printer_greenlet.link_exception(greenlet_exception_handler)\n\n    if options.csv_prefix:\n        gevent.spawn(stats_writer, environment, options.csv_prefix, full_history=options.stats_history_enabled).link_exception(greenlet_exception_handler)\n\n    \n    def shutdown(code=0):\n        \"\"\"\n        Shut down locust by firing quitting event, printing/writing stats and exiting\n        \"\"\"\n        logger.info(\"Shutting down (exit code %s), bye.\" % code)\n        if stats_printer_greenlet is not None:\n            stats_printer_greenlet.kill(block=False)\n        logger.info(\"Cleaning up runner...\")\n        if runner is not None:\n            runner.quit()\n        logger.info(\"Running teardowns...\")\n        environment.events.quitting.fire(reverse=True)\n        print_stats(runner.stats, current=False)\n        print_percentile_stats(runner.stats)\n        if options.csv_prefix:\n            write_csv_files(environment, options.csv_prefix, full_history=options.stats_history_enabled)\n        print_error_report(runner.stats)\n        sys.exit(code)\n    \n    # install SIGTERM handler\n    def sig_term_handler():\n        logger.info(\"Got SIGTERM signal\")\n        shutdown(0)\n    gevent.signal_handler(signal.SIGTERM, sig_term_handler)\n    \n    try:\n        logger.info(\"Starting Locust %s\" % version)\n        main_greenlet.join()\n        code = 0\n        if log.unhandled_greenlet_exception:\n            code = 2\n        elif len(runner.errors) or len(runner.exceptions):\n            code = options.exit_code_on_error\n        shutdown(code=code)\n    except KeyboardInterrupt as e:\n        shutdown(0)\n", "path": "locust/main.py"}], "after_files": [{"content": "import inspect\nimport logging\nimport os\nimport importlib\nimport signal\nimport socket\nimport sys\nimport time\nimport resource \n\nimport gevent\n\nimport locust\n\nfrom . import log\nfrom .argument_parser import parse_locustfile_option, parse_options\nfrom .env import Environment\nfrom .log import setup_logging, greenlet_exception_logger\nfrom .stats import (print_error_report, print_percentile_stats, print_stats,\n                    stats_printer, stats_writer, write_csv_files)\nfrom .user import User\nfrom .user.inspectuser import get_task_ratio_dict, print_task_ratio\nfrom .util.timespan import parse_timespan\nfrom .exception import AuthCredentialsError\n\nversion = locust.__version__\n\n\ndef is_user_class(item):\n    \"\"\"\n    Check if a variable is a runnable (non-abstract) User class\n    \"\"\"\n    return bool(\n        inspect.isclass(item)\n        and issubclass(item, User)\n        and item.abstract == False\n    )\n\n\ndef load_locustfile(path):\n    \"\"\"\n    Import given locustfile path and return (docstring, callables).\n\n    Specifically, the locustfile's ``__doc__`` attribute (a string) and a\n    dictionary of ``{'name': callable}`` containing all callables which pass\n    the \"is a Locust\" test.\n    \"\"\"\n\n    def __import_locustfile__(filename, path):\n        \"\"\"\n        Loads the locust file as a module, similar to performing `import`\n        \"\"\"\n        source = importlib.machinery.SourceFileLoader(os.path.splitext(locustfile)[0], path)\n        return  source.load_module()\n\n    # Start with making sure the current working dir is in the sys.path\n    sys.path.insert(0, os.getcwd())\n    # Get directory and locustfile name\n    directory, locustfile = os.path.split(path)\n    # If the directory isn't in the PYTHONPATH, add it so our import will work\n    added_to_path = False\n    index = None\n    if directory not in sys.path:\n        sys.path.insert(0, directory)\n        added_to_path = True\n    # If the directory IS in the PYTHONPATH, move it to the front temporarily,\n    # otherwise other locustfiles -- like Locusts's own -- may scoop the intended\n    # one.\n    else:\n        i = sys.path.index(directory)\n        if i != 0:\n            # Store index for later restoration\n            index = i\n            # Add to front, then remove from original position\n            sys.path.insert(0, directory)\n            del sys.path[i + 1]\n    # Perform the import\n    imported = __import_locustfile__(locustfile, path)\n    # Remove directory from path if we added it ourselves (just to be neat)\n    if added_to_path:\n        del sys.path[0]\n    # Put back in original index if we moved it\n    if index is not None:\n        sys.path.insert(index + 1, directory)\n        del sys.path[0]\n    # Return our two-tuple\n    user_classes = {name:value for name, value in vars(imported).items() if is_user_class(value)}\n    return imported.__doc__, user_classes\n\n\ndef create_environment(user_classes, options, events=None):\n    \"\"\"\n    Create an Environment instance from options\n    \"\"\"\n    return Environment(\n        user_classes=user_classes,\n        tags=options.tags,\n        exclude_tags=options.exclude_tags,\n        events=events,\n        host=options.host,\n        reset_stats=options.reset_stats,\n        step_load=options.step_load,\n        stop_timeout=options.stop_timeout,\n        parsed_options=options\n    )\n\n\ndef main():\n    # find specified locustfile and make sure it exists, using a very simplified\n    # command line parser that is only used to parse the -f option\n    locustfile = parse_locustfile_option()\n    \n    # import the locustfile\n    docstring, user_classes = load_locustfile(locustfile)\n    \n    # parse all command line options\n    options = parse_options()\n\n    if options.slave or options.expect_slaves:\n        sys.stderr.write(\"[DEPRECATED] Usage of slave has been deprecated, use --worker or --expect-workers\\n\")\n        sys.exit(1)\n    \n    # setup logging\n    if not options.skip_log_setup:\n        if options.loglevel.upper() in [\"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"]:\n            setup_logging(options.loglevel, options.logfile)\n        else:\n            sys.stderr.write(\"Invalid --loglevel. Valid values are: DEBUG/INFO/WARNING/ERROR/CRITICAL\\n\")\n            sys.exit(1)\n\n    logger = logging.getLogger(__name__)\n    greenlet_exception_handler = greenlet_exception_logger(logger)\n\n    if options.list_commands:\n        print(\"Available Users:\")\n        for name in user_classes:\n            print(\"    \" + name)\n        sys.exit(0)\n\n    if not user_classes:\n        logger.error(\"No User class found!\")\n        sys.exit(1)\n\n    # make sure specified User exists\n    if options.user_classes:\n        missing = set(options.user_classes) - set(user_classes.keys())\n        if missing:\n            logger.error(\"Unknown User(s): %s\\n\" % (\", \".join(missing)))\n            sys.exit(1)\n        else:\n            names = set(options.user_classes) & set(user_classes.keys())\n            user_classes = [user_classes[n] for n in names]\n    else:\n        # list() call is needed to consume the dict_view object in Python 3\n        user_classes = list(user_classes.values())\n    \n    try:\n        if resource.getrlimit(resource.RLIMIT_NOFILE)[0] < 10000:\n            # Increasing the limit to 10000 within a running process should work on at least MacOS.\n            # It does not work on all OS:es, but we should be no worse off for trying.\n            resource.setrlimit(resource.RLIMIT_NOFILE, [10000, resource.RLIM_INFINITY])\n    except:\n        logger.warning(\"System open file limit setting is not high enough for load testing, and the OS wouldnt allow locust to increase it by itself. See https://docs.locust.io/en/stable/installation.html#increasing-maximum-number-of-open-files-limit for more info.\")\n\n    # create locust Environment\n    environment = create_environment(user_classes, options, events=locust.events)\n    \n    if options.show_task_ratio:\n        print(\"\\n Task ratio per User class\")\n        print( \"-\" * 80)\n        print_task_ratio(user_classes)\n        print(\"\\n Total task ratio\")\n        print(\"-\" * 80)\n        print_task_ratio(user_classes, total=True)\n        sys.exit(0)\n    if options.show_task_ratio_json:\n        from json import dumps\n        task_data = {\n            \"per_class\": get_task_ratio_dict(user_classes),\n            \"total\": get_task_ratio_dict(user_classes, total=True)\n        }\n        print(dumps(task_data))\n        sys.exit(0)\n\n    if options.step_time:\n        if not options.step_load:\n            logger.error(\"The --step-time argument can only be used together with --step-load\")\n            sys.exit(1)\n        if options.worker:\n            logger.error(\"--step-time should be specified on the master node, and not on worker nodes\")\n            sys.exit(1)\n        try:\n            options.step_time = parse_timespan(options.step_time)\n        except ValueError:\n            logger.error(\"Valid --step-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.\")\n            sys.exit(1)\n    \n    if options.master:\n        runner = environment.create_master_runner(\n            master_bind_host=options.master_bind_host, \n            master_bind_port=options.master_bind_port,\n        )\n    elif options.worker:\n        try:\n            runner = environment.create_worker_runner(options.master_host, options.master_port)\n        except socket.error as e:\n            logger.error(\"Failed to connect to the Locust master: %s\", e)\n            sys.exit(-1)\n    else:\n        runner = environment.create_local_runner()\n    \n    # main_greenlet is pointing to runners.greenlet by default, it will point the web greenlet later if in web mode\n    main_greenlet = runner.greenlet\n    \n    if options.run_time:\n        if not options.headless:\n            logger.error(\"The --run-time argument can only be used together with --headless\")\n            sys.exit(1)\n        if options.worker:\n            logger.error(\"--run-time should be specified on the master node, and not on worker nodes\")\n            sys.exit(1)\n        try:\n            options.run_time = parse_timespan(options.run_time)\n        except ValueError:\n            logger.error(\"Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc.\")\n            sys.exit(1)\n        def spawn_run_time_limit_greenlet():\n            logger.info(\"Run time limit set to %s seconds\" % options.run_time)\n            def timelimit_stop():\n                logger.info(\"Time limit reached. Stopping Locust.\")\n                runner.quit()\n            gevent.spawn_later(options.run_time, timelimit_stop).link_exception(greenlet_exception_handler)\n    \n    # start Web UI\n    if not options.headless and not options.worker:\n        # spawn web greenlet\n        protocol = \"https\" if options.tls_cert and options.tls_key else \"http\"\n        logger.info(\"Starting web monitor at %s://%s:%s\" % (protocol, options.web_host, options.web_port))\n        try:\n            if options.web_host == \"*\":\n                # special check for \"*\" so that we're consistent with --master-bind-host\n                web_host = ''\n            else:\n                web_host = options.web_host\n            web_ui = environment.create_web_ui(\n                host=web_host, \n                port=options.web_port, \n                auth_credentials=options.web_auth, \n                tls_cert=options.tls_cert, \n                tls_key=options.tls_key,\n            )\n        except AuthCredentialsError:\n            logger.error(\"Credentials supplied with --web-auth should have the format: username:password\")\n            sys.exit(1)\n        else:\n            main_greenlet = web_ui.greenlet\n    else:\n        web_ui = None\n    \n    # Fire locust init event which can be used by end-users' code to run setup code that\n    # need access to the Environment, Runner or WebUI\n    environment.events.init.fire(environment=environment, runner=runner, web_ui=web_ui)    \n    \n    if options.headless:\n        # headless mode\n        if options.master:\n            # wait for worker nodes to connect\n            while len(runner.clients.ready) < options.expect_workers:\n                logging.info(\"Waiting for workers to be ready, %s of %s connected\",\n                             len(runner.clients.ready), options.expect_workers)\n                time.sleep(1)\n        if not options.worker:\n            # apply headless mode defaults\n            if options.num_users is None:\n                options.num_users = 1\n            if options.hatch_rate is None:\n                options.hatch_rate = 1\n            if options.step_users is None:\n                options.step_users = 1\n\n            # start the test\n            if options.step_time:\n                runner.start_stepload(options.num_users, options.hatch_rate, options.step_users, options.step_time)\n            else:\n                runner.start(options.num_users, options.hatch_rate)\n    \n    if options.run_time:\n        spawn_run_time_limit_greenlet()\n\n    stats_printer_greenlet = None\n    if not options.only_summary and (options.print_stats or (options.headless and not options.worker)):\n        # spawn stats printing greenlet\n        stats_printer_greenlet = gevent.spawn(stats_printer(runner.stats))\n        stats_printer_greenlet.link_exception(greenlet_exception_handler)\n\n    if options.csv_prefix:\n        gevent.spawn(stats_writer, environment, options.csv_prefix, full_history=options.stats_history_enabled).link_exception(greenlet_exception_handler)\n\n    \n    def shutdown(code=0):\n        \"\"\"\n        Shut down locust by firing quitting event, printing/writing stats and exiting\n        \"\"\"\n        logger.info(\"Shutting down (exit code %s), bye.\" % code)\n        if stats_printer_greenlet is not None:\n            stats_printer_greenlet.kill(block=False)\n        logger.info(\"Cleaning up runner...\")\n        if runner is not None:\n            runner.quit()\n        logger.info(\"Running teardowns...\")\n        environment.events.quitting.fire(reverse=True)\n        print_stats(runner.stats, current=False)\n        print_percentile_stats(runner.stats)\n        if options.csv_prefix:\n            write_csv_files(environment, options.csv_prefix, full_history=options.stats_history_enabled)\n        print_error_report(runner.stats)\n        sys.exit(code)\n    \n    # install SIGTERM handler\n    def sig_term_handler():\n        logger.info(\"Got SIGTERM signal\")\n        shutdown(0)\n    gevent.signal_handler(signal.SIGTERM, sig_term_handler)\n    \n    try:\n        logger.info(\"Starting Locust %s\" % version)\n        main_greenlet.join()\n        code = 0\n        if log.unhandled_greenlet_exception:\n            code = 2\n        elif len(runner.errors) or len(runner.exceptions):\n            code = options.exit_code_on_error\n        shutdown(code=code)\n    except KeyboardInterrupt as e:\n        shutdown(0)\n", "path": "locust/main.py"}]}