unique_toolkit 2026.32.0.dev4__py3-none-any.whl → 2026.32.0.dev5__py3-none-any.whl
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.
- unique_toolkit/monitoring/middleware.py +48 -10
- {unique_toolkit-2026.32.0.dev4.dist-info → unique_toolkit-2026.32.0.dev5.dist-info}/METADATA +2 -2
- {unique_toolkit-2026.32.0.dev4.dist-info → unique_toolkit-2026.32.0.dev5.dist-info}/RECORD +4 -4
- {unique_toolkit-2026.32.0.dev4.dist-info → unique_toolkit-2026.32.0.dev5.dist-info}/WHEEL +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
+
from collections.abc import Sequence
|
|
4
5
|
|
|
5
6
|
from prometheus_client import ( # pyright: ignore[reportMissingImports]
|
|
6
7
|
Counter,
|
|
@@ -16,12 +17,6 @@ _http_requests_total = Counter(
|
|
|
16
17
|
["method", "path", "status_code"],
|
|
17
18
|
registry=REGISTRY,
|
|
18
19
|
)
|
|
19
|
-
_http_request_duration_seconds = Histogram(
|
|
20
|
-
"python_http_request_duration_seconds",
|
|
21
|
-
"HTTP request duration",
|
|
22
|
-
["method", "path"],
|
|
23
|
-
registry=REGISTRY,
|
|
24
|
-
)
|
|
25
20
|
_http_requests_in_progress = Gauge(
|
|
26
21
|
"python_http_requests_in_progress",
|
|
27
22
|
"In-flight HTTP requests",
|
|
@@ -30,6 +25,35 @@ _http_requests_in_progress = Gauge(
|
|
|
30
25
|
multiprocess_mode="livesum",
|
|
31
26
|
)
|
|
32
27
|
|
|
28
|
+
# Created lazily on first MetricsMiddleware construction so services can choose the
|
|
29
|
+
# bucket layout. Prometheus allows a metric name to be registered only once per
|
|
30
|
+
# registry, so the buckets passed to the first middleware win for the process.
|
|
31
|
+
_http_request_duration_seconds: Histogram | None = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _get_or_create_duration_histogram(
|
|
35
|
+
buckets: Sequence[float] | None,
|
|
36
|
+
) -> Histogram:
|
|
37
|
+
global _http_request_duration_seconds
|
|
38
|
+
if _http_request_duration_seconds is None:
|
|
39
|
+
if buckets is None:
|
|
40
|
+
_http_request_duration_seconds = Histogram(
|
|
41
|
+
"python_http_request_duration_seconds",
|
|
42
|
+
"HTTP request duration",
|
|
43
|
+
["method", "path"],
|
|
44
|
+
registry=REGISTRY,
|
|
45
|
+
)
|
|
46
|
+
else:
|
|
47
|
+
_http_request_duration_seconds = Histogram(
|
|
48
|
+
"python_http_request_duration_seconds",
|
|
49
|
+
"HTTP request duration",
|
|
50
|
+
["method", "path"],
|
|
51
|
+
registry=REGISTRY,
|
|
52
|
+
buckets=tuple(buckets),
|
|
53
|
+
)
|
|
54
|
+
return _http_request_duration_seconds
|
|
55
|
+
|
|
56
|
+
|
|
33
57
|
_DEFAULT_EXCLUDED_PATHS = frozenset({"/health", "/metrics", "/"})
|
|
34
58
|
|
|
35
59
|
|
|
@@ -51,13 +75,29 @@ class MetricsMiddleware:
|
|
|
51
75
|
|
|
52
76
|
# Quart
|
|
53
77
|
app.asgi_app = MetricsMiddleware(app.asgi_app)
|
|
78
|
+
|
|
79
|
+
``duration_buckets`` overrides the latency histogram buckets (seconds). Without
|
|
80
|
+
it, prometheus_client's defaults apply and their top finite bucket is 10s —
|
|
81
|
+
histogram_quantile cannot resolve past the largest finite bucket, so services
|
|
82
|
+
with slower endpoints should pass buckets covering their full latency range::
|
|
83
|
+
|
|
84
|
+
app.add_middleware(MetricsMiddleware, duration_buckets=(1, 5, 30, 60, 120))
|
|
85
|
+
|
|
86
|
+
The histogram is registered once per process; the buckets of the first
|
|
87
|
+
constructed middleware apply.
|
|
54
88
|
"""
|
|
55
89
|
|
|
56
|
-
def __init__(
|
|
90
|
+
def __init__(
|
|
91
|
+
self,
|
|
92
|
+
app,
|
|
93
|
+
excluded_paths: set[str] | None = None,
|
|
94
|
+
duration_buckets: Sequence[float] | None = None,
|
|
95
|
+
):
|
|
57
96
|
self.app = app
|
|
58
97
|
self._excluded_paths = (
|
|
59
98
|
excluded_paths if excluded_paths is not None else _DEFAULT_EXCLUDED_PATHS
|
|
60
99
|
)
|
|
100
|
+
self._duration = _get_or_create_duration_histogram(duration_buckets)
|
|
61
101
|
|
|
62
102
|
async def __call__(self, scope, receive, send):
|
|
63
103
|
# Pass through non-HTTP (WebSocket, lifespan)
|
|
@@ -87,9 +127,7 @@ class MetricsMiddleware:
|
|
|
87
127
|
finally:
|
|
88
128
|
duration = time.perf_counter() - start
|
|
89
129
|
_http_requests_in_progress.labels(method=method).dec()
|
|
90
|
-
|
|
91
|
-
duration
|
|
92
|
-
)
|
|
130
|
+
self._duration.labels(method=method, path=path).observe(duration)
|
|
93
131
|
_http_requests_total.labels(
|
|
94
132
|
method=method, path=path, status_code=status_code
|
|
95
133
|
).inc()
|
{unique_toolkit-2026.32.0.dev4.dist-info → unique_toolkit-2026.32.0.dev5.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 2026.32.0.
|
|
3
|
+
Version: 2026.32.0.dev5
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Cedric Klinkert, Martin Fadler, Sadique Sheik, Fabian Schläpfer, Pascal Hauri, Ejiroghene Oki-Peter, Rami Azouz, Ricardo Visini, Sanzio Monti
|
|
6
6
|
Author-email: Cedric Klinkert <cedric.klinkert@unique.ch>, Martin Fadler <martin.fadler@unique.ch>, Sadique Sheik <sadique@unique.ch>, Fabian Schläpfer <fabian@unique.ch>, Pascal Hauri <pascal@unique.ch>, Ejiroghene Oki-Peter <oki-peter.ejiroghene@unique.ai>, Rami Azouz <rami.ext@unique.ch>, Ricardo Visini <ricardo.visini@unique.ch>, Sanzio Monti <sanzio.monti@unique.ai>
|
|
@@ -16,7 +16,7 @@ Requires-Dist: sseclient>=0.0.27,<0.0.28
|
|
|
16
16
|
Requires-Dist: openai>=1.105.0,<3
|
|
17
17
|
Requires-Dist: platformdirs>=4.0.0,<5
|
|
18
18
|
Requires-Dist: pillow>=12.1.1
|
|
19
|
-
Requires-Dist: unique-sdk>=2026.32.0.
|
|
19
|
+
Requires-Dist: unique-sdk>=2026.32.0.dev8,<2026.32.0rc0
|
|
20
20
|
Requires-Dist: jambo>=0.1.2,<0.2
|
|
21
21
|
Requires-Dist: jinja2>=3.1.6,<4
|
|
22
22
|
Requires-Dist: docxtpl>=0.20.1,<0.21
|
|
@@ -403,7 +403,7 @@ unique_toolkit/language_model/stream_transform.py,sha256=iNNGpLY_7G6Bpp9Y4KtbIkQ
|
|
|
403
403
|
unique_toolkit/language_model/utils.py,sha256=bPQ4l6_YO71w-zaIPanUUmtbXC1_hCvLK0tAFc3VCRc,1902
|
|
404
404
|
unique_toolkit/monitoring/__init__.py,sha256=z1gkOCLxGcg936MFuLSeWFa0tREcBFSUbV09NxilBw4,1065
|
|
405
405
|
unique_toolkit/monitoring/gunicorn.py,sha256=urTFFS5zYHKoxb1TEQHcLqb2byi-aYgFRHGwgYRzYYI,844
|
|
406
|
-
unique_toolkit/monitoring/middleware.py,sha256=
|
|
406
|
+
unique_toolkit/monitoring/middleware.py,sha256=MNsUuKgt74mSnUwttXTB_AxX546Pz2zKoAP9OewVrwQ,4531
|
|
407
407
|
unique_toolkit/monitoring/registry.py,sha256=De2Bx5QBBRJQY2MM3xtntiJ2JU2FoKkVT7rNMG7ewgA,5874
|
|
408
408
|
unique_toolkit/protocols/support.py,sha256=x5edzbBmKAUuvm3oLFh52gkgQsqR5LU7M0t8RHK0DZk,5161
|
|
409
409
|
unique_toolkit/services/__init__.py,sha256=b9Wl7Wvz1JmZDbDexIZzBoXZ0wscXuczGAH8LoL-Qak,572
|
|
@@ -418,6 +418,6 @@ unique_toolkit/short_term_memory/service.py,sha256=2JMBEBn6GoyK-a0xvdcWpPft-3C74
|
|
|
418
418
|
unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
419
419
|
unique_toolkit/smart_rules/compile.py,sha256=vRe0aMJWuVIK-VsqomgxQImzke7MDmwgSxxJfYCa7zw,1386
|
|
420
420
|
unique_toolkit/test_utilities/events.py,sha256=FLrhMh0A_mQutAUjoD0FdMcVQ4Gq31r35OVGzRjvLro,6760
|
|
421
|
-
unique_toolkit-2026.32.0.
|
|
422
|
-
unique_toolkit-2026.32.0.
|
|
423
|
-
unique_toolkit-2026.32.0.
|
|
421
|
+
unique_toolkit-2026.32.0.dev5.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
422
|
+
unique_toolkit-2026.32.0.dev5.dist-info/METADATA,sha256=1bEknHHM6C2M0YX9ZPdElqUVEOA1AnI_u-_zmXVKrQM,7465
|
|
423
|
+
unique_toolkit-2026.32.0.dev5.dist-info/RECORD,,
|
|
File without changes
|