Skip to content

Commit

Permalink
New Default Metric: Requests In Progress (stephenhillier#27)
Browse files Browse the repository at this point in the history
* ignore .vscode project folder settings

* correction in new metric code block

* added pytest dependency into requirements.txt

* added request_in_progress gauge

* Update starlette_exporter/middleware.py

Co-authored-by: Steve Hillier <[email protected]>

* Update starlette_exporter/middleware.py

Co-authored-by: Steve Hillier <[email protected]>

* Update starlette_exporter/middleware.py

Co-authored-by: Steve Hillier <[email protected]>

* Update starlette_exporter/middleware.py

Co-authored-by: Steve Hillier <[email protected]>

* remove 'buckets' for gauge metric type

* test for requests_in_progress

Co-authored-by: Steve Hillier <[email protected]>
  • Loading branch information
scotgopal and stephenhillier authored Jul 14, 2021
1 parent 574be1b commit 9be76c5
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ venv.bak/
# Rope project settings
.ropeproject

# VS Code project settings
.vscode

# mkdocs documentation
/site

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ The new metric will now be included in the the `/metrics` endpoint output:

```
...
redirect_total{from="some_view"} 2.0
redirect_total{redirected_from="some_view"} 2.0
...
```

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ prometheus-client==0.7.1
starlette==0.12.9
requests==2.22.0
aiofiles==0.7.0
pytest==6.2.4
19 changes: 18 additions & 1 deletion starlette_exporter/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from typing import List, Optional, ClassVar, Dict

from prometheus_client import Counter, Histogram
from prometheus_client import Counter, Histogram, Gauge
from prometheus_client.metrics import MetricWrapperBase
from starlette.requests import Request
from starlette.routing import Route, Match, Mount
Expand Down Expand Up @@ -80,6 +80,18 @@ def request_time(self):
)
return PrometheusMiddleware._metrics[metric_name]

@property
def requests_in_progress(self):
metric_name = f"{self.prefix}_requests_in_progress"
if metric_name not in PrometheusMiddleware._metrics:
PrometheusMiddleware._metrics[metric_name] = Gauge(
metric_name,
"Total HTTP requests currently in progress",
("method", "app_name"),
multiprocess_mode="livesum"
)
return PrometheusMiddleware._metrics[metric_name]

async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope["type"] not in ["http"]:
await self.app(scope, receive, send)
Expand All @@ -92,6 +104,9 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
begin = time.perf_counter()
end = None

# Increment requests_in_progress gauge when request comes in
self.requests_in_progress.labels(method, self.app_name).inc()

# Default status code used when the application does not return a valid response
# or an unhandled exception occurs.
status_code = 500
Expand Down Expand Up @@ -132,6 +147,8 @@ async def wrapped_send(message: Message) -> None:

self.request_count.labels(*labels).inc()
self.request_time.labels(*labels).observe(end - begin)
# Decrement 'requests_in_progress' gauge after response sent
self.requests_in_progress.labels(method, self.app_name).dec()

@staticmethod
def _get_router_path(scope: Scope) -> Optional[str]:
Expand Down
23 changes: 23 additions & 0 deletions tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,29 @@ def test_multi_prefix(self, testapp):
in metrics2
)

def test_requests_in_progress(self, client):
""" test that the requests_in_progress metric (a gauge) is incremented after one request.
This test is fairly trivial and doesn't cover decrementing at the end of the request.
TODO: create a second asyncronous request and check that the counter is incremented
multiple times (and decremented back to zero when all requests done).
"""

metrics = client.get('/metrics').content.decode()
assert (
"""starlette_requests_in_progress{app_name="starlette",method="GET"} 1.0"""
in metrics
)

# try a second time as an alternate way to check that the requests_in_progress metric
# was decremented at the end of the first request. This test could be improved, but
# at the very least, it checks that the gauge wasn't incremented multiple times without
# also being decremented.
metrics = client.get('/metrics').content.decode()
assert (
"""starlette_requests_in_progress{app_name="starlette",method="GET"} 1.0"""
in metrics
)


class TestMiddlewareGroupedPaths:
""" tests for group_paths option (using named parameters to group endpoint metrics with path params together) """
Expand Down

0 comments on commit 9be76c5

Please sign in to comment.