strobengine 0.6.0__tar.gz → 0.7.0__tar.gz

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.
Files changed (101) hide show
  1. {strobengine-0.6.0 → strobengine-0.7.0}/CHANGELOG.md +87 -0
  2. {strobengine-0.6.0 → strobengine-0.7.0}/Cargo.lock +201 -1
  3. {strobengine-0.6.0 → strobengine-0.7.0}/Cargo.toml +3 -1
  4. {strobengine-0.6.0 → strobengine-0.7.0}/PKG-INFO +1 -1
  5. {strobengine-0.6.0 → strobengine-0.7.0}/docs/cli.md +3 -0
  6. {strobengine-0.6.0 → strobengine-0.7.0}/docs/reports.md +24 -3
  7. {strobengine-0.6.0 → strobengine-0.7.0}/docs/roadmap.md +8 -8
  8. {strobengine-0.6.0 → strobengine-0.7.0}/pyproject.toml +1 -1
  9. {strobengine-0.6.0 → strobengine-0.7.0}/src/chaos.rs +2 -0
  10. {strobengine-0.6.0 → strobengine-0.7.0}/src/config.rs +333 -152
  11. {strobengine-0.6.0 → strobengine-0.7.0}/src/lib.rs +166 -261
  12. strobengine-0.7.0/src/metrics/mod.rs +1190 -0
  13. strobengine-0.7.0/src/metrics/system.rs +263 -0
  14. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/grpc.rs +35 -15
  15. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/http.rs +11 -4
  16. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/http3.rs +42 -19
  17. strobengine-0.7.0/src/protocols/mod.rs +273 -0
  18. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/sse.rs +61 -23
  19. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/websocket.rs +71 -23
  20. {strobengine-0.6.0 → strobengine-0.7.0}/src/report/mod.rs +0 -1
  21. {strobengine-0.6.0 → strobengine-0.7.0}/src/report/schema.rs +66 -10
  22. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/_strobengine.pyi +28 -12
  23. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/cli.py +169 -60
  24. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/engine.py +79 -57
  25. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporter.py +125 -19
  26. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/assets/report_template.html +63 -0
  27. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/html_report.py +3 -0
  28. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_http_scenarios.py +20 -0
  29. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_persistence_e2e.py +41 -2
  30. {strobengine-0.6.0 → strobengine-0.7.0}/tests/test_cli.py +25 -0
  31. {strobengine-0.6.0 → strobengine-0.7.0}/tests/test_engine.py +32 -13
  32. {strobengine-0.6.0 → strobengine-0.7.0}/tests/test_reporting.py +186 -2
  33. {strobengine-0.6.0 → strobengine-0.7.0}/uv.lock +1 -1
  34. strobengine-0.6.0/src/metrics.rs +0 -714
  35. strobengine-0.6.0/src/protocols/mod.rs +0 -124
  36. strobengine-0.6.0/src/report/writer.rs +0 -280
  37. {strobengine-0.6.0 → strobengine-0.7.0}/.dockerignore +0 -0
  38. {strobengine-0.6.0 → strobengine-0.7.0}/.github/workflows/ci.yml +0 -0
  39. {strobengine-0.6.0 → strobengine-0.7.0}/.github/workflows/docker-release.yml +0 -0
  40. {strobengine-0.6.0 → strobengine-0.7.0}/.github/workflows/publish-test.yml +0 -0
  41. {strobengine-0.6.0 → strobengine-0.7.0}/.github/workflows/publish.yml +0 -0
  42. {strobengine-0.6.0 → strobengine-0.7.0}/.gitignore +0 -0
  43. {strobengine-0.6.0 → strobengine-0.7.0}/.pre-commit-config.yaml +0 -0
  44. {strobengine-0.6.0 → strobengine-0.7.0}/.python-version +0 -0
  45. {strobengine-0.6.0 → strobengine-0.7.0}/Dockerfile +0 -0
  46. {strobengine-0.6.0 → strobengine-0.7.0}/LICENSE +0 -0
  47. {strobengine-0.6.0 → strobengine-0.7.0}/Makefile +0 -0
  48. {strobengine-0.6.0 → strobengine-0.7.0}/README.md +0 -0
  49. {strobengine-0.6.0 → strobengine-0.7.0}/cliff.toml +0 -0
  50. {strobengine-0.6.0 → strobengine-0.7.0}/docs/benchmarks.md +0 -0
  51. {strobengine-0.6.0 → strobengine-0.7.0}/docs/dependencies.md +0 -0
  52. {strobengine-0.6.0 → strobengine-0.7.0}/docs/docker.md +0 -0
  53. {strobengine-0.6.0 → strobengine-0.7.0}/docs/grpc.md +0 -0
  54. {strobengine-0.6.0 → strobengine-0.7.0}/docs/http3.md +0 -0
  55. {strobengine-0.6.0 → strobengine-0.7.0}/docs/http_methods.md +0 -0
  56. {strobengine-0.6.0 → strobengine-0.7.0}/docs/infrastructure.md +0 -0
  57. {strobengine-0.6.0 → strobengine-0.7.0}/docs/install.md +0 -0
  58. {strobengine-0.6.0 → strobengine-0.7.0}/docs/quickstart.md +0 -0
  59. {strobengine-0.6.0 → strobengine-0.7.0}/docs/release.md +0 -0
  60. {strobengine-0.6.0 → strobengine-0.7.0}/docs/sse.md +0 -0
  61. {strobengine-0.6.0 → strobengine-0.7.0}/docs/table_of_contents.md +0 -0
  62. {strobengine-0.6.0 → strobengine-0.7.0}/docs/testing.md +0 -0
  63. {strobengine-0.6.0 → strobengine-0.7.0}/docs/websockets.md +0 -0
  64. {strobengine-0.6.0 → strobengine-0.7.0}/examples/grpc.py +0 -0
  65. {strobengine-0.6.0 → strobengine-0.7.0}/examples/http3.py +0 -0
  66. {strobengine-0.6.0 → strobengine-0.7.0}/examples/http_methods.py +0 -0
  67. {strobengine-0.6.0 → strobengine-0.7.0}/examples/load_test.py +0 -0
  68. {strobengine-0.6.0 → strobengine-0.7.0}/examples/spike_test.py +0 -0
  69. {strobengine-0.6.0 → strobengine-0.7.0}/examples/sse.py +0 -0
  70. {strobengine-0.6.0 → strobengine-0.7.0}/examples/stress_test.py +0 -0
  71. {strobengine-0.6.0 → strobengine-0.7.0}/examples/websocket.py +0 -0
  72. {strobengine-0.6.0 → strobengine-0.7.0}/rust-toolchain.toml +0 -0
  73. {strobengine-0.6.0 → strobengine-0.7.0}/scripts/release.py +0 -0
  74. {strobengine-0.6.0 → strobengine-0.7.0}/src/logging.rs +0 -0
  75. {strobengine-0.6.0 → strobengine-0.7.0}/src/progress.rs +0 -0
  76. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/grpc_parser.rs +0 -0
  77. {strobengine-0.6.0 → strobengine-0.7.0}/src/protocols/grpc_reflection.rs +0 -0
  78. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/__init__.py +0 -0
  79. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/constants.py +0 -0
  80. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/py.typed +0 -0
  81. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/__init__.py +0 -0
  82. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/assets/chart.min.js +0 -0
  83. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/baseline.py +0 -0
  84. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/csv_report.py +0 -0
  85. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/junit_report.py +0 -0
  86. {strobengine-0.6.0 → strobengine-0.7.0}/src/strobengine/reporting/markdown_report.py +0 -0
  87. {strobengine-0.6.0 → strobengine-0.7.0}/tests/__init__.py +0 -0
  88. {strobengine-0.6.0 → strobengine-0.7.0}/tests/conftest.py +0 -0
  89. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/__init__.py +0 -0
  90. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/conftest.py +0 -0
  91. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/mock_server.py +0 -0
  92. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_cli_interface.py +0 -0
  93. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_grpc_e2e.py +0 -0
  94. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_http3_e2e.py +0 -0
  95. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_latency_stats_e2e.py +0 -0
  96. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_performance_sanity.py +0 -0
  97. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_sse_e2e.py +0 -0
  98. {strobengine-0.6.0 → strobengine-0.7.0}/tests/e2e/test_websocket_e2e.py +0 -0
  99. {strobengine-0.6.0 → strobengine-0.7.0}/tests/fixtures/service.proto +0 -0
  100. {strobengine-0.6.0 → strobengine-0.7.0}/tests/test_logging.py +0 -0
  101. {strobengine-0.6.0 → strobengine-0.7.0}/tests/test_reporter.py +0 -0
@@ -4,6 +4,89 @@ All notable changes to `strobengine` will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.7.0] - 2026-09-21
8
+
9
+ ### Bug Fixes
10
+
11
+ - *(orchestration)* Run aggregator concurrently to prevent bounded channel deadlock
12
+ - *(grpc)* Return explicit ProtoError on invalid hex and base64 payloads
13
+ - *(worker)* Add timeout guards for context creation and session teardown
14
+ - *(cli)* Forward export options from subcommands to _run_load_test
15
+ - *(metrics)* Handle missing PID gracefully in resource monitor sampler
16
+ - *(sse)* Replace fragile unwrap in persistent stream with safe let-else
17
+ - *(cli)* Surface FFI and export errors with friendly messages
18
+ - *(reporter)* Use try/finally for atomic write cleanup in save_report
19
+
20
+ ### Documentation
21
+
22
+ - *(reporter)* Add cross-language schema references and contract tests
23
+ - *(reports)* Update filename pattern and persistence ownership
24
+ - Document resource monitoring, system_metrics schema, and CLI option
25
+ - Mark connection pool metrics complete and add to JSON schema docs
26
+
27
+ ### Features
28
+
29
+ - *(ffi)* Expose build_report_artifact_dict for Python artifact parity
30
+ - *(protocols)* Return Result from detect_protocol to eliminate silent fallbacks
31
+ - *(metrics)* Add ResourceMonitor with sampler worker and ResourceSample
32
+ - *(cli)* Wire resource monitor through config and CLI options
33
+ - *(metrics)* Add SystemMetrics struct with aggregated resource stats
34
+ - *(report)* Include system_metrics in TestSummary JSON and ReportArtifact
35
+ - *(reporting)* Format system metrics for terminal and Jinja context
36
+ - *(html)* Add dual-axis Chart.js client resource footprint section
37
+ - *(metrics)* Add DNS resolution and connection reuse tracking
38
+ - *(protocols)* Instrument DNS resolution and socket reuse across engines
39
+ - *(report)* Add connection pool metrics to ReportArtifact and JSON export
40
+
41
+ ### Miscellaneous Tasks
42
+
43
+ - *(report)* Remove dead writer.rs module and tests
44
+
45
+ ### Refactoring
46
+
47
+ - *(metrics)* Extract SummaryInput struct for calculate_summary
48
+ - *(cli)* Extract _run_load_test helper and fix E2E test failures
49
+ - *(metrics)* Centralize histogram bucket order via PyO3 constant
50
+ - *(metrics)* Group connection fields into ConnectionMetrics struct
51
+ - *(metrics)* Extract finalize_metrics logic to helper module
52
+ - *(metrics)* Introduce AggregatedMetrics struct
53
+ - *(report)* Align ReportArtifact serde with Python artifact schema
54
+ - *(reporter)* Delegate build_artifact_dict to Rust for schema parity
55
+ - *(reporter)* Make save_report atomic with latest.json pointer
56
+ - *(engine)* Consolidate artifact persistence into StrobEngine.run()
57
+ - *(cli)* Remove duplicate save_report from _output_results
58
+ - *(lib)* Remove artifact write from Rust run_load_test
59
+ - *(protocols)* Replace Box<dyn Any> with typed WorkerSession trait
60
+ - *(config)* Introduce TestConfigBuilder and remove dead option structs
61
+ - *(lib)* Make run_load_profiles accept TestConfig for capability parity
62
+ - *(engine)* Build TestConfig for all execution profiles in Python
63
+ - *(metrics)* Replace unbounded Vec<u128> with HDR Histograms
64
+ - *(lib)* Extract shared build_engine helper from run_load_test/profiles
65
+
66
+ ### Testing
67
+
68
+ - *(e2e)* Update persistence tests for Python artifact writer
69
+ - *(reporting)* Add schema edge-case and parity tests
70
+ - *(metrics)* Add unit and integration tests for connection pool and DNS metrics
71
+ - *(reporter)* Cover save_report temp-file cleanup
72
+ ## [0.6.1] - 2026-09-13
73
+
74
+ ### Bug Fixes
75
+
76
+ - *(lib)* Remove unnecessary clippy::too_many_arguments suppression
77
+
78
+ ### Features
79
+
80
+ - *(reporter)* Use dynamic terminal width for histogram bar rendering
81
+
82
+ ### Miscellaneous Tasks
83
+
84
+ - *(release)* Bump version to 0.6.1
85
+
86
+ ### Refactoring
87
+
88
+ - *(schema)* Derive LatencyPercentiles from TestSummary via From impl
89
+ - *(engine)* Clone TestSummary before enrichment to prevent in-place mutation
7
90
  ## [0.6.0] - 2026-09-09
8
91
 
9
92
  ### Bug Fixes
@@ -32,6 +115,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
32
115
  - *(metrics)* Add latency jitter, p99.99, and histogram bucketing
33
116
  - *(reporter)* Expose extended latency stats in terminal and artifact output
34
117
 
118
+ ### Miscellaneous Tasks
119
+
120
+ - *(release)* Bump version to 0.6.0
121
+
35
122
  ### Refactoring
36
123
 
37
124
  - *(lib)* Extract spawn_worker helper from execute_test
@@ -2,6 +2,12 @@
2
2
  # It is not intended for manual editing.
3
3
  version = 4
4
4
 
5
+ [[package]]
6
+ name = "adler2"
7
+ version = "2.0.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
10
+
5
11
  [[package]]
6
12
  name = "aho-corasick"
7
13
  version = "1.1.4"
@@ -139,6 +145,12 @@ version = "3.20.3"
139
145
  source = "registry+https://github.com/rust-lang/crates.io-index"
140
146
  checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
141
147
 
148
+ [[package]]
149
+ name = "byteorder"
150
+ version = "1.5.0"
151
+ source = "registry+https://github.com/rust-lang/crates.io-index"
152
+ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
153
+
142
154
  [[package]]
143
155
  name = "bytes"
144
156
  version = "1.12.1"
@@ -245,6 +257,30 @@ dependencies = [
245
257
  "libc",
246
258
  ]
247
259
 
260
+ [[package]]
261
+ name = "crc32fast"
262
+ version = "1.5.2"
263
+ source = "registry+https://github.com/rust-lang/crates.io-index"
264
+ checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
265
+ dependencies = [
266
+ "cfg-if",
267
+ ]
268
+
269
+ [[package]]
270
+ name = "crossbeam-channel"
271
+ version = "0.5.17"
272
+ source = "registry+https://github.com/rust-lang/crates.io-index"
273
+ checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1"
274
+ dependencies = [
275
+ "crossbeam-utils",
276
+ ]
277
+
278
+ [[package]]
279
+ name = "crossbeam-utils"
280
+ version = "0.8.23"
281
+ source = "registry+https://github.com/rust-lang/crates.io-index"
282
+ checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
283
+
248
284
  [[package]]
249
285
  name = "crypto-common"
250
286
  version = "0.1.7"
@@ -328,6 +364,17 @@ version = "0.1.9"
328
364
  source = "registry+https://github.com/rust-lang/crates.io-index"
329
365
  checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
330
366
 
367
+ [[package]]
368
+ name = "flate2"
369
+ version = "1.1.10"
370
+ source = "registry+https://github.com/rust-lang/crates.io-index"
371
+ checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb"
372
+ dependencies = [
373
+ "crc32fast",
374
+ "miniz_oxide",
375
+ "zlib-rs",
376
+ ]
377
+
331
378
  [[package]]
332
379
  name = "fnv"
333
380
  version = "1.0.7"
@@ -539,6 +586,20 @@ version = "0.17.1"
539
586
  source = "registry+https://github.com/rust-lang/crates.io-index"
540
587
  checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
541
588
 
589
+ [[package]]
590
+ name = "hdrhistogram"
591
+ version = "7.6.0"
592
+ source = "registry+https://github.com/rust-lang/crates.io-index"
593
+ checksum = "f49d1053f4708f0af3cf9fc5bffc7e68a914a3c45becb231c80068c9c3f78bea"
594
+ dependencies = [
595
+ "base64",
596
+ "byteorder",
597
+ "crossbeam-channel",
598
+ "flate2",
599
+ "nom",
600
+ "num-traits",
601
+ ]
602
+
542
603
  [[package]]
543
604
  name = "heck"
544
605
  version = "0.5.0"
@@ -1049,6 +1110,16 @@ version = "0.3.17"
1049
1110
  source = "registry+https://github.com/rust-lang/crates.io-index"
1050
1111
  checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
1051
1112
 
1113
+ [[package]]
1114
+ name = "miniz_oxide"
1115
+ version = "0.9.1"
1116
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1117
+ checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c"
1118
+ dependencies = [
1119
+ "adler2",
1120
+ "simd-adler32",
1121
+ ]
1122
+
1052
1123
  [[package]]
1053
1124
  name = "mio"
1054
1125
  version = "1.2.2"
@@ -1060,6 +1131,24 @@ dependencies = [
1060
1131
  "windows-sys 0.61.2",
1061
1132
  ]
1062
1133
 
1134
+ [[package]]
1135
+ name = "nom"
1136
+ version = "8.0.0"
1137
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1138
+ checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
1139
+ dependencies = [
1140
+ "memchr",
1141
+ ]
1142
+
1143
+ [[package]]
1144
+ name = "ntapi"
1145
+ version = "0.4.3"
1146
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1147
+ checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae"
1148
+ dependencies = [
1149
+ "winapi",
1150
+ ]
1151
+
1063
1152
  [[package]]
1064
1153
  name = "nu-ansi-term"
1065
1154
  version = "0.50.3"
@@ -1078,6 +1167,15 @@ dependencies = [
1078
1167
  "autocfg",
1079
1168
  ]
1080
1169
 
1170
+ [[package]]
1171
+ name = "objc2-core-foundation"
1172
+ version = "0.3.2"
1173
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1174
+ checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
1175
+ dependencies = [
1176
+ "bitflags",
1177
+ ]
1178
+
1081
1179
  [[package]]
1082
1180
  name = "once_cell"
1083
1181
  version = "1.21.4"
@@ -1739,6 +1837,12 @@ dependencies = [
1739
1837
  "libc",
1740
1838
  ]
1741
1839
 
1840
+ [[package]]
1841
+ name = "simd-adler32"
1842
+ version = "0.3.10"
1843
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1844
+ checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
1845
+
1742
1846
  [[package]]
1743
1847
  name = "simd_cesu8"
1744
1848
  version = "1.2.0"
@@ -1785,7 +1889,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
1785
1889
 
1786
1890
  [[package]]
1787
1891
  name = "strobengine"
1788
- version = "0.6.0"
1892
+ version = "0.7.0"
1789
1893
  dependencies = [
1790
1894
  "async-trait",
1791
1895
  "base64",
@@ -1794,6 +1898,7 @@ dependencies = [
1794
1898
  "futures-util",
1795
1899
  "h3",
1796
1900
  "h3-quinn",
1901
+ "hdrhistogram",
1797
1902
  "hex",
1798
1903
  "http",
1799
1904
  "indicatif",
@@ -1807,6 +1912,7 @@ dependencies = [
1807
1912
  "reqwest",
1808
1913
  "serde",
1809
1914
  "serde_json",
1915
+ "sysinfo",
1810
1916
  "tokio",
1811
1917
  "tokio-stream",
1812
1918
  "tokio-tungstenite",
@@ -1867,6 +1973,19 @@ dependencies = [
1867
1973
  "syn 2.0.119",
1868
1974
  ]
1869
1975
 
1976
+ [[package]]
1977
+ name = "sysinfo"
1978
+ version = "0.34.2"
1979
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1980
+ checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2"
1981
+ dependencies = [
1982
+ "libc",
1983
+ "memchr",
1984
+ "ntapi",
1985
+ "objc2-core-foundation",
1986
+ "windows",
1987
+ ]
1988
+
1870
1989
  [[package]]
1871
1990
  name = "target-lexicon"
1872
1991
  version = "0.13.5"
@@ -2420,6 +2539,22 @@ dependencies = [
2420
2539
  "rustls-pki-types",
2421
2540
  ]
2422
2541
 
2542
+ [[package]]
2543
+ name = "winapi"
2544
+ version = "0.3.9"
2545
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2546
+ checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
2547
+ dependencies = [
2548
+ "winapi-i686-pc-windows-gnu",
2549
+ "winapi-x86_64-pc-windows-gnu",
2550
+ ]
2551
+
2552
+ [[package]]
2553
+ name = "winapi-i686-pc-windows-gnu"
2554
+ version = "0.4.0"
2555
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2556
+ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
2557
+
2423
2558
  [[package]]
2424
2559
  name = "winapi-util"
2425
2560
  version = "0.1.11"
@@ -2429,12 +2564,71 @@ dependencies = [
2429
2564
  "windows-sys 0.61.2",
2430
2565
  ]
2431
2566
 
2567
+ [[package]]
2568
+ name = "winapi-x86_64-pc-windows-gnu"
2569
+ version = "0.4.0"
2570
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2571
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
2572
+
2573
+ [[package]]
2574
+ name = "windows"
2575
+ version = "0.57.0"
2576
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2577
+ checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
2578
+ dependencies = [
2579
+ "windows-core",
2580
+ "windows-targets",
2581
+ ]
2582
+
2583
+ [[package]]
2584
+ name = "windows-core"
2585
+ version = "0.57.0"
2586
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2587
+ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
2588
+ dependencies = [
2589
+ "windows-implement",
2590
+ "windows-interface",
2591
+ "windows-result",
2592
+ "windows-targets",
2593
+ ]
2594
+
2595
+ [[package]]
2596
+ name = "windows-implement"
2597
+ version = "0.57.0"
2598
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2599
+ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
2600
+ dependencies = [
2601
+ "proc-macro2",
2602
+ "quote",
2603
+ "syn 2.0.119",
2604
+ ]
2605
+
2606
+ [[package]]
2607
+ name = "windows-interface"
2608
+ version = "0.57.0"
2609
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2610
+ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
2611
+ dependencies = [
2612
+ "proc-macro2",
2613
+ "quote",
2614
+ "syn 2.0.119",
2615
+ ]
2616
+
2432
2617
  [[package]]
2433
2618
  name = "windows-link"
2434
2619
  version = "0.2.1"
2435
2620
  source = "registry+https://github.com/rust-lang/crates.io-index"
2436
2621
  checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
2437
2622
 
2623
+ [[package]]
2624
+ name = "windows-result"
2625
+ version = "0.1.2"
2626
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2627
+ checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
2628
+ dependencies = [
2629
+ "windows-targets",
2630
+ ]
2631
+
2438
2632
  [[package]]
2439
2633
  name = "windows-sys"
2440
2634
  version = "0.52.0"
@@ -2632,6 +2826,12 @@ dependencies = [
2632
2826
  "syn 2.0.119",
2633
2827
  ]
2634
2828
 
2829
+ [[package]]
2830
+ name = "zlib-rs"
2831
+ version = "0.6.8"
2832
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2833
+ checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112"
2834
+
2635
2835
  [[package]]
2636
2836
  name = "zmij"
2637
2837
  version = "1.0.23"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "strobengine"
3
- version = "0.6.0"
3
+ version = "0.7.0"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -44,3 +44,5 @@ quinn = { version = "0.11", default-features = false, features = ["runtime-tokio
44
44
  h3 = "0.0.8"
45
45
  h3-quinn = "0.0.10"
46
46
  webpki-roots = "0.26"
47
+ hdrhistogram = "7"
48
+ sysinfo = "0.34"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: strobengine
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Requires-Dist: rich>=13.0.0
5
5
  Requires-Dist: typer>=0.27.0
6
6
  Requires-Dist: jinja2>=3.1
@@ -45,6 +45,7 @@ By default, this spawns **10 concurrent workers** for **10 seconds** with a **10
45
45
  | `--quic-max-idle-timeout` | none | QUIC max idle timeout in ms |
46
46
  | `--sse/--no-sse` | off | Enable SSE streaming mode |
47
47
  | `--sse-max-events` | none | Maximum events to receive per connection |
48
+ | `--sys-sample-interval` | `1000` | Resource monitor sample interval in ms (0 to disable) |
48
49
 
49
50
  ## Stress Subcommand Options
50
51
 
@@ -79,6 +80,7 @@ By default, this spawns **10 concurrent workers** for **10 seconds** with a **10
79
80
  | `--quic-max-idle-timeout` | none | QUIC max idle timeout in ms |
80
81
  | `--sse/--no-sse` | off | Enable SSE streaming mode |
81
82
  | `--sse-max-events` | none | Maximum events to receive per connection |
83
+ | `--sys-sample-interval` | `1000` | Resource monitor sample interval in ms (0 to disable) |
82
84
 
83
85
  ## Spike Subcommand Options
84
86
 
@@ -114,6 +116,7 @@ By default, this spawns **10 concurrent workers** for **10 seconds** with a **10
114
116
  | `--quic-max-idle-timeout` | none | QUIC max idle timeout in ms |
115
117
  | `--sse/--no-sse` | off | Enable SSE streaming mode |
116
118
  | `--sse-max-events` | none | Maximum events to receive per connection |
119
+ | `--sys-sample-interval` | `1000` | Resource monitor sample interval in ms (0 to disable) |
117
120
 
118
121
  ## Global Options
119
122
 
@@ -12,12 +12,12 @@ to disk by default.
12
12
  | Property | Value |
13
13
  |----------|-------|
14
14
  | Default directory | `./.strobengine/reports/` |
15
- | Filename pattern | `report_YYYYMMDD_HHMMSS_<host>.json` |
15
+ | Filename pattern | `{timestamp}_{slug}.json` (e.g., `2026-08-28T10_00_00+00_00_localhost_8080.json`) |
16
16
  | Atomic writes | Yes — tmp file + rename prevents corruption |
17
17
  | `latest.json` pointer | Yes — tracks most recent report |
18
18
 
19
- Reports are written by both the Rust engine (`run_load_test`) and
20
- the Python reporter (`save_report`).
19
+ Reports are written by the Python reporter (`save_report`) inside
20
+ `StrobEngine.run()` with atomic writes and `latest.json` pointer management.
21
21
 
22
22
  ## Configuration Flags
23
23
 
@@ -47,6 +47,8 @@ These flags appear on all three subcommands (`load`, `stress`, `spike`):
47
47
  | `quic` | `zero_rtt_accepted_count`, `retransmissions`, `avg_handshake_ms` *(HTTP/3 only)* |
48
48
  | `sse` | `total_events_received`, `avg_ttfb_ms` *(SSE only)* |
49
49
  | `chaos_faults` | `injected_total`, `by_type` *(chaos-enabled runs only)* |
50
+ | `system_metrics` | `summary` (peak/avg CPU, memory MB, threads), `samples` (time series) *(when `--sys-sample-interval > 0`)* |
51
+ | `connection_pool` | `socket_creation_rate`, `socket_reuse_rate`, `dns_lookup_ms` *(when requests > 0)* |
50
52
 
51
53
  All latency values are stored in **microseconds**.
52
54
 
@@ -74,6 +76,24 @@ All latency values are stored in **microseconds**.
74
76
  "LatencySpike": 4,
75
77
  "CorruptedPayload": 3
76
78
  }
79
+ },
80
+ "system_metrics": {
81
+ "summary": {
82
+ "peak_cpu_percent": 45.2,
83
+ "avg_cpu_percent": 18.1,
84
+ "peak_memory_mb": 64.5,
85
+ "avg_memory_mb": 52.3,
86
+ "peak_threads": 32
87
+ },
88
+ "samples": [
89
+ { "elapsed_sec": 1.0, "cpu_percent": 12.4, "memory_mb": 42.1, "threads": 16 },
90
+ { "elapsed_sec": 2.0, "cpu_percent": 24.8, "memory_mb": 51.0, "threads": 28 }
91
+ ]
92
+ },
93
+ "connection_pool": {
94
+ "socket_creation_rate": 0.25,
95
+ "socket_reuse_rate": 0.75,
96
+ "dns_lookup_ms": 1.5
77
97
  }
78
98
  }
79
99
  ```
@@ -99,6 +119,7 @@ strobengine load http://localhost:8080/api -c 10 -d 30 --html report.html
99
119
  - **Dark theme** — slate/navy color palette
100
120
  - **Bar chart**: Latency percentiles (P50, P90, P95, P99) in milliseconds
101
121
  - **Doughnut chart**: Status code distribution (2xx, 4xx, 5xx, Other)
122
+ - **Line chart**: Client resource footprint (CPU % + Memory RSS, dual-axis) when `--sys-sample-interval > 0`
102
123
  - **Metadata grid**: Target URL, method, concurrency, duration, RPS, error rate
103
124
 
104
125
  ### Python API
@@ -33,7 +33,7 @@ This document outlines the planned trajectory and upcoming feature epics for **s
33
33
 
34
34
  - [x] Interactive CLI progress indicators (live RPS, active virtual users, latency feed). `[v0.2.0]`
35
35
  - [ ] ~~Real-time telemetry dashboard / TUI integration.~~ *(Postponed: Python scripting is primary runner; CLI is for quick drafts only)*
36
- - [ ] ~~Improved streaming metrics collection to minimize memory overhead during long runs.~~ *(Deferred until $O(1)$ memory metrics are required for multi-hour runs)*
36
+ - [ ] ~~Improved streaming metrics collection to minimize memory overhead during long runs.~~ *(Completed: replaced unbounded Vec<u128> with hdrhistogram::Histogram<u64> for O(1) memory)*
37
37
 
38
38
  ---
39
39
 
@@ -100,14 +100,14 @@ This document outlines the planned trajectory and upcoming feature epics for **s
100
100
  - [x] Add p99.99 percentile
101
101
  - [x] Add latency histogram buckets for distribution visualization
102
102
 
103
- - [ ] **Client System Resource Monitoring** `[v0.7.0]`
104
- - [ ] Track engine CPU %, memory (RSS), thread count during test
105
- - [ ] Sample at configurable interval (e.g., every 1s)
106
- - [ ] Include in JSON report artifact and HTML visualization
103
+ - [x] **Client System Resource Monitoring** `[v0.7.0]`
104
+ - [x] Track engine CPU %, memory (RSS), thread count during test
105
+ - [x] Sample at configurable interval via `--sys-sample-interval` (default 1000ms, 0 to disable)
106
+ - [x] Include in JSON report artifact (`system_metrics` field) and HTML visualization (dual-axis Chart.js line chart)
107
107
 
108
- - [ ] **Connection Pool Metrics** `[v0.7.0]`
109
- - [ ] Track socket creation rate vs reuse rate
110
- - [ ] Report DNS resolution duration (if instrumentable)
108
+ - [x] **Connection Pool Metrics** `[v0.7.0]`
109
+ - [x] Track socket creation rate vs reuse rate
110
+ - [x] Report DNS resolution duration (if instrumentable)
111
111
 
112
112
  - [ ] **Protocol-Specific Deep Metrics** `[v0.8.0]`
113
113
  - [ ] WebSocket: unsolicited pings/pongs, backpressure depth
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "strobengine"
3
- version = "0.6.0"
3
+ version = "0.7.0"
4
4
  description = "A load testing framework with a Python UI and a bare-metal Rust engine core."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -23,7 +23,9 @@ impl ChaosFault {
23
23
 
24
24
  #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
25
25
  pub struct ChaosMetrics {
26
+ #[serde(rename = "injected_total")]
26
27
  pub total_injected: u64,
28
+ #[serde(rename = "by_type")]
27
29
  pub faults_by_type: HashMap<String, u64>,
28
30
  }
29
31