Skip to content

Commit cb5f559

Browse files
committed
feat: locustio#2955 Allow to exclude some statistics from aggregation
1 parent ab5faf3 commit cb5f559

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

locust/env.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
from operator import methodcaller
4-
from typing import Callable, TypeVar
4+
from re import Pattern
5+
from typing import Callable, TypeVar, Optional
56

67
from configargparse import Namespace
78

@@ -27,6 +28,7 @@ def __init__(
2728
tags: list[str] | None = None,
2829
locustfile: str | None = None,
2930
exclude_tags: list[str] | None = None,
31+
exclude_from_aggregation: Optional[str | Pattern[str]] = None,
3032
events: Events | None = None,
3133
host: str | None = None,
3234
reset_stats=False,
@@ -69,7 +71,7 @@ def __init__(
6971
"""If set, only tasks that are tagged by tags in this list will be executed. Leave this as None to use the one from parsed_options"""
7072
self.exclude_tags = exclude_tags
7173
"""If set, only tasks that aren't tagged by tags in this list will be executed. Leave this as None to use the one from parsed_options"""
72-
self.stats = RequestStats()
74+
self.stats = RequestStats(environment=self)
7375
"""Reference to RequestStats instance"""
7476
self.host = host
7577
"""Base URL of the target system"""
@@ -154,7 +156,7 @@ def create_worker_runner(self, master_host: str, master_port: int) -> WorkerRunn
154156
"""
155157
# Create a new RequestStats with use_response_times_cache set to False to save some memory
156158
# and CPU cycles, since the response_times_cache is not needed for Worker nodes
157-
self.stats = RequestStats(use_response_times_cache=False)
159+
self.stats = RequestStats(use_response_times_cache=False, environment=self)
158160
return self._create_runner(
159161
WorkerRunner,
160162
master_host=master_host,

locust/stats.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import json
66
import logging
77
import os
8+
import re
89
import signal
910
import time
1011
from abc import abstractmethod
@@ -14,7 +15,7 @@
1415
from html import escape
1516
from itertools import chain
1617
from types import FrameType
17-
from typing import TYPE_CHECKING, Any, Callable, NoReturn, Protocol, TypedDict, TypeVar, cast
18+
from typing import TYPE_CHECKING, Any, Callable, NoReturn, Optional, Protocol, TypedDict, TypeVar, cast
1819

1920
import gevent
2021

@@ -184,17 +185,19 @@ class RequestStats:
184185
Class that holds the request statistics. Accessible in a User from self.environment.stats
185186
"""
186187

187-
def __init__(self, use_response_times_cache=True):
188+
def __init__(self, use_response_times_cache=True, environment: Optional[Environment]=None):
188189
"""
189190
:param use_response_times_cache: The value of use_response_times_cache will be set for each StatsEntry()
190191
when they are created. Settings it to False saves some memory and CPU
191192
cycles which we can do on Worker nodes where the response_times_cache
192193
is not needed.
194+
:param environment: The environment context.
193195
"""
194196
self.use_response_times_cache = use_response_times_cache
195197
self.entries: dict[tuple[str, str], StatsEntry] = EntriesDict(self)
196198
self.errors: dict[str, StatsError] = {}
197199
self.total = StatsEntry(self, "Aggregated", None, use_response_times_cache=self.use_response_times_cache)
200+
self.environment = environment
198201
self.history = []
199202

200203
@property
@@ -217,8 +220,17 @@ def last_request_timestamp(self):
217220
def start_time(self):
218221
return self.total.start_time
219222

223+
def exclude_from_total(self, method: str, name: str):
224+
exclude_from_aggregation = getattr(getattr(self, "environment", None), "exclude_from_aggregation", None)
225+
if exclude_from_aggregation:
226+
found_in_method = re.search(exclude_from_aggregation, method)
227+
found_in_name = re.search(exclude_from_aggregation, name)
228+
return found_in_method or found_in_name
229+
return False
230+
220231
def log_request(self, method: str, name: str, response_time: int, content_length: int) -> None:
221-
self.total.log(response_time, content_length)
232+
if not self.exclude_from_total(method, name):
233+
self.total.log(response_time, content_length)
222234
self.entries[(name, method)].log(response_time, content_length)
223235

224236
def log_error(self, method: str, name: str, error: Exception | str | None) -> None:

locust/test/test_stats.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,17 @@ def test_total_rps(self):
9898
self.assertAlmostEqual(s2.total_rps, 1 / 5.0)
9999
self.assertEqual(self.stats.total.total_rps, 10 / 5.0)
100100

101+
def test_total_exclude_from_aggregation(self):
102+
env = Environment()
103+
self.stats.environment = env
104+
# First without exclusion
105+
self.stats.log_request("CUSTOM", "some_name", 1337, 1337)
106+
self.assertEqual(self.stats.num_requests(), 1)
107+
# Second with exclusion
108+
env.exclude_from_aggregation = r"CUSTOM"
109+
self.stats.log_request("CUSTOM", "some_name", 1337, 1337)
110+
self.assertEqual(self.stats.num_requests(), 1)
111+
101112
def test_rps_less_than_one_second(self):
102113
s = StatsEntry(self.stats, "percentile_test", "GET")
103114
for i in range(10):

0 commit comments

Comments
 (0)