or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

contrib.mddebugging.mdevents.mdexceptions.mdindex.mdload-shapes.mdtasksets.mduser-classes.mdwait-time.md

events.mddocs/

0

# Events System

1

2

Locust's event system provides extensibility hooks for custom metrics, logging, integrations, and test lifecycle management. The global `events` instance offers access to all built-in events for extending Locust functionality.

3

4

## Capabilities

5

6

### Global Events Instance

7

8

The primary interface for accessing Locust's event system, available as a global instance.

9

10

```python { .api }

11

from locust import events

12

13

# Global events instance providing access to all event hooks

14

events: Events

15

```

16

17

### Core Request Events

18

19

Events fired during HTTP request lifecycle for statistics collection and custom processing.

20

21

```python { .api }

22

# Request completion event

23

events.request.add_listener(handler)

24

25

def request_handler(request_type, name, response_time, response_length, exception=None, **kwargs):

26

"""

27

Handle request completion events.

28

29

Args:

30

request_type (str): HTTP method or custom request type

31

name (str): Request name for statistics grouping

32

response_time (float): Response time in milliseconds

33

response_length (int): Response body length in bytes

34

exception (Exception): Exception if request failed

35

**kwargs: Additional request metadata

36

"""

37

38

# User error event

39

events.user_error.add_listener(handler)

40

41

def user_error_handler(user_instance, exception, tb, **kwargs):

42

"""

43

Handle user execution errors.

44

45

Args:

46

user_instance: User instance that encountered error

47

exception (Exception): Exception that occurred

48

tb: Traceback object

49

**kwargs: Additional error context

50

"""

51

```

52

53

### Test Lifecycle Events

54

55

Events for hooking into test execution phases and managing test lifecycle.

56

57

```python { .api }

58

# Test initialization

59

events.init.add_listener(handler)

60

61

def init_handler(environment, **kwargs):

62

"""

63

Handle test initialization.

64

65

Args:

66

environment: Locust environment instance

67

**kwargs: Additional initialization context

68

"""

69

70

# Test start

71

events.test_start.add_listener(handler)

72

73

def test_start_handler(environment, **kwargs):

74

"""

75

Handle test start event.

76

77

Args:

78

environment: Locust environment instance

79

**kwargs: Additional test start context

80

"""

81

82

# Test stopping (before cleanup)

83

events.test_stopping.add_listener(handler)

84

85

def test_stopping_handler(environment, **kwargs):

86

"""

87

Handle test stopping event (before cleanup).

88

89

Args:

90

environment: Locust environment instance

91

**kwargs: Additional context

92

"""

93

94

# Test stop (after cleanup)

95

events.test_stop.add_listener(handler)

96

97

def test_stop_handler(environment, **kwargs):

98

"""

99

Handle test stop event (after cleanup).

100

101

Args:

102

environment: Locust environment instance

103

**kwargs: Additional context

104

"""

105

106

# Test quit (final cleanup)

107

events.quit.add_listener(handler)

108

events.quitting.add_listener(handler)

109

110

def quit_handler(exit_code, **kwargs):

111

"""

112

Handle test quit events.

113

114

Args:

115

exit_code (int): Exit code for test run

116

**kwargs: Additional quit context

117

"""

118

```

119

120

### User Lifecycle Events

121

122

Events related to user spawning and management during test execution.

123

124

```python { .api }

125

# User spawning complete

126

events.spawning_complete.add_listener(handler)

127

128

def spawning_complete_handler(user_count, **kwargs):

129

"""

130

Handle user spawning completion.

131

132

Args:

133

user_count (int): Total number of spawned users

134

**kwargs: Additional spawning context

135

"""

136

```

137

138

### Statistics Events

139

140

Events for custom statistics handling and processing.

141

142

```python { .api }

143

# Statistics reset

144

events.reset_stats.add_listener(handler)

145

146

def reset_stats_handler(**kwargs):

147

"""

148

Handle statistics reset event.

149

150

Args:

151

**kwargs: Reset context

152

"""

153

```

154

155

### Distributed Testing Events

156

157

Events for master/worker coordination in distributed testing scenarios.

158

159

```python { .api }

160

# Worker reporting to master

161

events.report_to_master.add_listener(handler)

162

163

def report_to_master_handler(client_id, data, **kwargs):

164

"""

165

Handle worker report to master.

166

167

Args:

168

client_id (str): Worker client identifier

169

data (dict): Report data from worker

170

**kwargs: Additional report context

171

"""

172

173

# Master receiving worker report

174

events.worker_report.add_listener(handler)

175

176

def worker_report_handler(client_id, data, **kwargs):

177

"""

178

Handle worker report on master.

179

180

Args:

181

client_id (str): Worker client identifier

182

data (dict): Report data from worker

183

**kwargs: Additional report context

184

"""

185

186

# Worker connect to master

187

events.worker_connect.add_listener(handler)

188

189

def worker_connect_handler(client_id, **kwargs):

190

"""

191

Handle worker connection to master.

192

193

Args:

194

client_id (str): Worker client identifier

195

**kwargs: Connection context

196

"""

197

```

198

199

### System Monitoring Events

200

201

Events for system resource monitoring and alerts.

202

203

```python { .api }

204

# CPU usage warning

205

events.cpu_warning.add_listener(handler)

206

207

def cpu_warning_handler(usage_percent, **kwargs):

208

"""

209

Handle CPU usage warnings.

210

211

Args:

212

usage_percent (float): CPU usage percentage

213

**kwargs: Additional system context

214

"""

215

216

# Heartbeat events (distributed testing)

217

events.heartbeat_sent.add_listener(handler)

218

events.heartbeat_received.add_listener(handler)

219

220

def heartbeat_handler(client_id, **kwargs):

221

"""

222

Handle heartbeat events.

223

224

Args:

225

client_id (str): Client identifier

226

**kwargs: Heartbeat context

227

"""

228

229

# Usage monitoring

230

events.usage_monitor.add_listener(handler)

231

232

def usage_monitor_handler(stats, **kwargs):

233

"""

234

Handle usage monitoring events.

235

236

Args:

237

stats (dict): Usage statistics

238

**kwargs: Monitoring context

239

"""

240

```

241

242

### Command Line Events

243

244

Events for customizing command line argument parsing.

245

246

```python { .api }

247

# Command line parser initialization

248

events.init_command_line_parser.add_listener(handler)

249

250

def init_parser_handler(parser, **kwargs):

251

"""

252

Handle command line parser initialization.

253

254

Args:

255

parser: ArgumentParser instance

256

**kwargs: Parser initialization context

257

"""

258

```

259

260

## Event Classes

261

262

### Events Class

263

264

Main events manager class for creating custom event systems.

265

266

```python { .api }

267

class Events:

268

"""

269

Event system manager providing event hooks.

270

271

Attributes:

272

request: Request completion event hook

273

user_error: User error event hook

274

report_to_master: Worker to master reporting hook

275

worker_report: Master receiving worker report hook

276

worker_connect: Worker connection hook

277

spawning_complete: User spawning completion hook

278

quitting: Test quitting hook

279

quit: Test quit hook

280

init: Test initialization hook

281

init_command_line_parser: CLI parser init hook

282

test_start: Test start hook

283

test_stopping: Test stopping hook

284

test_stop: Test stop hook

285

reset_stats: Statistics reset hook

286

cpu_warning: CPU usage warning hook

287

heartbeat_sent: Heartbeat sent hook

288

heartbeat_received: Heartbeat received hook

289

usage_monitor: Usage monitoring hook

290

"""

291

```

292

293

### EventHook Class

294

295

Individual event hook implementation for subscribing and firing events.

296

297

```python { .api }

298

class EventHook:

299

"""

300

Individual event hook for managing event listeners.

301

"""

302

303

def add_listener(self, func):

304

"""

305

Add event listener function.

306

307

Args:

308

func (callable): Event handler function

309

"""

310

311

def remove_listener(self, func):

312

"""

313

Remove event listener function.

314

315

Args:

316

func (callable): Event handler function to remove

317

"""

318

319

def fire(self, **kwargs):

320

"""

321

Fire event to all registered listeners.

322

323

Args:

324

**kwargs: Event data to pass to listeners

325

"""

326

```

327

328

## Usage Examples

329

330

### Custom Metrics Collection

331

332

```python

333

from locust import HttpUser, task, between, events

334

import time

335

import json

336

337

# Custom metrics storage

338

custom_metrics = {

339

"api_calls": 0,

340

"error_count": 0,

341

"response_times": []

342

}

343

344

def on_request(request_type, name, response_time, response_length, exception, **kwargs):

345

"""Collect custom metrics on each request"""

346

custom_metrics["api_calls"] += 1

347

custom_metrics["response_times"].append(response_time)

348

349

if exception:

350

custom_metrics["error_count"] += 1

351

352

# Log slow requests

353

if response_time > 5000: # 5 seconds

354

print(f"SLOW REQUEST: {name} took {response_time}ms")

355

356

def on_test_stop(environment, **kwargs):

357

"""Report custom metrics at test end"""

358

total_calls = custom_metrics["api_calls"]

359

avg_response_time = sum(custom_metrics["response_times"]) / len(custom_metrics["response_times"])

360

error_rate = custom_metrics["error_count"] / total_calls * 100

361

362

print(f"\n--- Custom Metrics ---")

363

print(f"Total API calls: {total_calls}")

364

print(f"Average response time: {avg_response_time:.2f}ms")

365

print(f"Error rate: {error_rate:.2f}%")

366

367

# Save to file

368

with open("custom_metrics.json", "w") as f:

369

json.dump(custom_metrics, f, indent=2)

370

371

# Register event listeners

372

events.request.add_listener(on_request)

373

events.test_stop.add_listener(on_test_stop)

374

375

class APIUser(HttpUser):

376

wait_time = between(1, 3)

377

378

@task

379

def api_call(self):

380

self.client.get("/api/data")

381

```

382

383

### External System Integration

384

385

```python

386

from locust import HttpUser, task, events

387

import requests

388

import json

389

390

class ExternalReporter:

391

def __init__(self, webhook_url):

392

self.webhook_url = webhook_url

393

self.test_start_time = None

394

self.request_count = 0

395

396

def on_test_start(self, environment, **kwargs):

397

"""Notify external system of test start"""

398

self.test_start_time = time.time()

399

payload = {

400

"event": "test_start",

401

"timestamp": self.test_start_time,

402

"users": environment.runner.target_user_count if environment.runner else 0

403

}

404

self.send_webhook(payload)

405

406

def on_request(self, request_type, name, response_time, response_length, exception, **kwargs):

407

"""Track request metrics"""

408

self.request_count += 1

409

410

# Send alerts for errors

411

if exception:

412

payload = {

413

"event": "error",

414

"timestamp": time.time(),

415

"request_type": request_type,

416

"name": name,

417

"error": str(exception)

418

}

419

self.send_webhook(payload)

420

421

def on_test_stop(self, environment, **kwargs):

422

"""Send final test report"""

423

duration = time.time() - self.test_start_time

424

payload = {

425

"event": "test_complete",

426

"timestamp": time.time(),

427

"duration": duration,

428

"total_requests": self.request_count,

429

"stats": environment.stats.serialize_stats() if environment.stats else {}

430

}

431

self.send_webhook(payload)

432

433

def send_webhook(self, payload):

434

"""Send webhook notification"""

435

try:

436

requests.post(self.webhook_url, json=payload, timeout=5)

437

except Exception as e:

438

print(f"Webhook failed: {e}")

439

440

# Initialize external reporter

441

reporter = ExternalReporter("https://monitoring.example.com/webhook")

442

443

# Register event listeners

444

events.test_start.add_listener(reporter.on_test_start)

445

events.request.add_listener(reporter.on_request)

446

events.test_stop.add_listener(reporter.on_test_stop)

447

448

class WebUser(HttpUser):

449

wait_time = between(1, 2)

450

451

@task

452

def browse(self):

453

self.client.get("/")

454

```

455

456

### Custom Statistics and Reporting

457

458

```python

459

from locust import HttpUser, task, events

460

import csv

461

import time

462

from collections import defaultdict

463

464

class DetailedStats:

465

def __init__(self):

466

self.start_time = time.time()

467

self.requests_by_minute = defaultdict(list)

468

self.errors_by_type = defaultdict(int)

469

self.response_time_buckets = defaultdict(int)

470

471

def on_request(self, request_type, name, response_time, response_length, exception, **kwargs):

472

"""Collect detailed request statistics"""

473

minute = int((time.time() - self.start_time) // 60)

474

475

# Track requests per minute

476

self.requests_by_minute[minute].append({

477

"type": request_type,

478

"name": name,

479

"response_time": response_time,

480

"length": response_length,

481

"success": exception is None

482

})

483

484

# Track errors by type

485

if exception:

486

error_type = type(exception).__name__

487

self.errors_by_type[error_type] += 1

488

489

# Response time buckets

490

if response_time < 100:

491

self.response_time_buckets["<100ms"] += 1

492

elif response_time < 500:

493

self.response_time_buckets["100-500ms"] += 1

494

elif response_time < 1000:

495

self.response_time_buckets["500ms-1s"] += 1

496

elif response_time < 5000:

497

self.response_time_buckets["1-5s"] += 1

498

else:

499

self.response_time_buckets[">5s"] += 1

500

501

def on_test_stop(self, environment, **kwargs):

502

"""Generate detailed CSV report"""

503

with open("detailed_stats.csv", "w", newline="") as csvfile:

504

writer = csv.writer(csvfile)

505

writer.writerow(["Minute", "Request_Type", "Name", "Response_Time", "Length", "Success"])

506

507

for minute, requests in self.requests_by_minute.items():

508

for req in requests:

509

writer.writerow([

510

minute, req["type"], req["name"],

511

req["response_time"], req["length"], req["success"]

512

])

513

514

# Print summary

515

print("\n--- Response Time Distribution ---")

516

for bucket, count in self.response_time_buckets.items():

517

print(f"{bucket}: {count} requests")

518

519

print("\n--- Error Summary ---")

520

for error_type, count in self.errors_by_type.items():

521

print(f"{error_type}: {count} occurrences")

522

523

# Initialize detailed stats collector

524

stats_collector = DetailedStats()

525

events.request.add_listener(stats_collector.on_request)

526

events.test_stop.add_listener(stats_collector.on_test_stop)

527

528

class AnalyticsUser(HttpUser):

529

wait_time = between(0.5, 2)

530

531

@task(3)

532

def page_view(self):

533

self.client.get("/page")

534

535

@task(1)

536

def api_call(self):

537

self.client.get("/api/data")

538

```

539

540

### Environment-Specific Event Handling

541

542

```python

543

from locust import HttpUser, task, events

544

import os

545

546

def setup_environment_specific_handlers():

547

"""Setup different event handlers based on environment"""

548

environment = os.getenv("TEST_ENV", "development")

549

550

if environment == "production":

551

# Production: minimal logging, external monitoring

552

def prod_error_handler(user_instance, exception, tb, **kwargs):

553

# Send to external monitoring service

554

send_to_monitoring_service(str(exception))

555

556

events.user_error.add_listener(prod_error_handler)

557

558

elif environment == "staging":

559

# Staging: detailed logging for debugging

560

def staging_request_handler(request_type, name, response_time, response_length, exception, **kwargs):

561

if exception or response_time > 2000:

562

print(f"STAGING ALERT: {name} - {response_time}ms - {exception}")

563

564

events.request.add_listener(staging_request_handler)

565

566

else:

567

# Development: verbose logging

568

def dev_request_handler(**kwargs):

569

print(f"DEV REQUEST: {kwargs}")

570

571

events.request.add_listener(dev_request_handler)

572

573

# Setup environment-specific handling

574

setup_environment_specific_handlers()

575

576

class EnvironmentUser(HttpUser):

577

wait_time = between(1, 3)

578

579

@task

580

def environment_test(self):

581

self.client.get("/api/environment")

582

```

583

584

## Types

585

586

```python { .api }

587

from typing import Callable, Any, Dict, Optional

588

from locust.env import Environment

589

590

# Event handler function types

591

RequestHandler = Callable[[str, str, float, int, Optional[Exception]], None]

592

UserErrorHandler = Callable[[Any, Exception, Any], None]

593

LifecycleHandler = Callable[[Environment], None]

594

StatisticsHandler = Callable[[Dict[str, Any]], None]

595

SystemHandler = Callable[[float], None] # For CPU warnings, etc.

596

597

# Generic event handler

598

EventHandler = Callable[..., None]

599

600

# Event hook interface

601

class EventHook:

602

def add_listener(self, func: EventHandler) -> None: ...

603

def remove_listener(self, func: EventHandler) -> None: ...

604

def fire(self, **kwargs: Any) -> None: ...

605

```