Source code for locust.event

from __future__ import annotations

import logging
import time
import traceback
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any

from . import log
from .exception import InterruptTaskSet, RescheduleTask, RescheduleTaskImmediately, StopUser


[docs] class EventHook: """ Simple event class used to provide hooks for different types of events in Locust. Here's how to use the EventHook class:: my_event = EventHook() def on_my_event(a, b, **kw): print("Event was fired with arguments: %s, %s" % (a, b)) my_event.add_listener(on_my_event) my_event.fire(a="foo", b="bar") If reverse is True, then the handlers will run in the reverse order that they were inserted """ def __init__(self): self._handlers = [] def add_listener(self, handler): self._handlers.append(handler) return handler def remove_listener(self, handler): self._handlers.remove(handler) def fire(self, *, reverse=False, **kwargs): if reverse: handlers = reversed(self._handlers) else: handlers = self._handlers for handler in handlers: try: handler(**kwargs) except (StopUser, RescheduleTask, RescheduleTaskImmediately, InterruptTaskSet): # These exceptions could be thrown by, for example, a request handler, # in which case they are entirely appropriate and should not be caught raise except Exception: logging.error("Uncaught exception in event handler: \n%s", traceback.format_exc()) log.unhandled_greenlet_exception = True
[docs] @contextmanager def measure( self, request_type: str, name: str, response_length: int = 0, context=None ) -> Generator[dict[str, Any]]: """Convenience method for firing the event with automatically calculated response time and automatically marking the request as failed if an exception is raised (this is really only useful for the *request* event) Example usage (in a task): .. code-block:: python with self.environment.events.request.measure("requestType", "requestName") as request_meta: # do the stuff you want to measure You can optionally add/overwrite entries in the request_meta dict and they will be passed to the request event. Experimental. """ start_time = time.time() start_perf_counter = time.perf_counter() request_meta = { "request_type": request_type, "name": name, "response_length": response_length, "context": context or {}, "exception": None, "start_time": start_time, } try: yield request_meta except Exception as e: request_meta["exception"] = e finally: request_meta["response_time"] = (time.perf_counter() - start_perf_counter) * 1000 self.fire(**request_meta)
class DeprecatedEventHook(EventHook): def __init__(self, message): self.message = message super().__init__() def add_listener(self, handler): logging.warning(self.message) return super().add_listener(handler)
[docs] class Events: request: EventHook """ Fired when a request in completed. Event arguments: :param request_type: Request type method used :param name: Path to the URL that was called (or override name if it was used in the call to the client) :param response_time: Time in milliseconds until exception was thrown :param response_length: Content-length of the response :param response: Response object (e.g. a :py:class:`requests.Response`) :param context: :ref:`User/request context <request_context>` :param exception: Exception instance that was thrown. None if request was successful. If you want to simplify a custom client, you can have Locust measure the time for you by using :meth:`measure() <locust.event.EventHook.measure>` """ user_error: EventHook """ Fired when an exception occurs inside the execution of a User class. Event arguments: :param user_instance: User class instance where the exception occurred :param exception: Exception that was thrown :param tb: Traceback object (from e.__traceback__) """ report_to_master: EventHook """ Used when Locust is running in --worker mode. It can be used to attach data to the dicts that are regularly sent to the master. It's fired regularly when a report is to be sent to the master server. Note that the keys "stats" and "errors" are used by Locust and shouldn't be overridden. Event arguments: :param client_id: The client id of the running locust process. :param data: Data dict that can be modified in order to attach data that should be sent to the master. """ worker_report: EventHook """ Used when Locust is running in --master mode and is fired when the master server receives a report from a Locust worker server. This event can be used to aggregate data from the locust worker servers. Event arguments: :param client_id: Client id of the reporting worker :param data: Data dict with the data from the worker node """ worker_connect: EventHook """ Fired on master when a new worker connects. Note that is fired immediately after the connection is established, so init event may not yet have finished on worker. :param client_id: Client id of the connected worker """ spawning_complete: EventHook """ Fired when all simulated users has been spawned. The event is fired on master first, and then distributed to workers. Event arguments: :param user_count: Number of users that were spawned (in total, not per-worker) """ quitting: EventHook """ Fired when the locust process is exiting. Event arguments: :param environment: Environment instance """ quit: EventHook """ Fired after quitting events, just before process is exited. Event arguments: :param exit_code: Exit code for process """ init: EventHook """ Fired when Locust is started, once the Environment instance and locust runner instance have been created. This hook can be used by end-users' code to run code that requires access to the Environment. For example to register listeners to other events. Event arguments: :param environment: Environment instance """ init_command_line_parser: EventHook """ Event that can be used to add command line options to Locust Event arguments: :param parser: ArgumentParser instance """ test_start: EventHook """ Fired on each node when a new load test is started. It's not fired again if the number of users change during a test. """ test_stopping: EventHook """ Fired on each node when a load test is about to stop - before stopping users. """ test_stop: EventHook """ Fired on each node when a load test is stopped. """ reset_stats: EventHook """ Fired when the Reset Stats button is clicked in the web UI. """ cpu_warning: EventHook """ Fired when the CPU usage exceeds runners.CPU_WARNING_THRESHOLD (90% by default) """ heartbeat_sent: EventHook """ Fired when a heartbeat is sent by master to a worker. Event arguments: :param client_id: worker client id :param timestamp: time in seconds since the epoch (float) when the event occured """ heartbeat_received: EventHook """ Fired when a heartbeat is received by a worker from master. Event arguments: :param client_id: worker client id :param timestamp: time in seconds since the epoch (float) when the event occured """ usage_monitor: EventHook """ Fired every runners.CPU_MONITOR_INTERVAL (5.0 seconds by default) with information about current CPU and memory usage. Event arguments: :param environment: locust environment :param cpu_usage: current CPU usage in percent :param memory_usage: current memory usage (RSS) in bytes """ def __init__(self): # For backward compatibility use also values of class attributes for name, value in vars(type(self)).items(): if value == "EventHook": setattr(self, name, EventHook()) for name, value in self.__annotations__.items(): if value == "EventHook": setattr(self, name, EventHook())