Skip to content

Commit

Permalink
Merge pull request #99 from stephenhillier/response-labels-exceptions
Browse files Browse the repository at this point in the history
ensure response header labels are populated during exceptions
  • Loading branch information
stephenhillier committed Jun 26, 2024
2 parents ef3a18b + bd1581e commit 8fafd31
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
3 changes: 1 addition & 2 deletions starlette_exporter/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import Any, Callable, Iterable, Optional, Dict

from starlette.requests import Request
from starlette.types import Message


class ResponseHeaderLabel:
Expand All @@ -13,7 +12,7 @@ class ResponseHeaderLabel:
def __init__(
self, key: str, allowed_values: Optional[Iterable] = None, default: str = ""
) -> None:
self.key = key
self.key = key.lower()
self.default = default
self.allowed_values = allowed_values

Expand Down
6 changes: 5 additions & 1 deletion starlette_exporter/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def _response_label_values(self, message: Message) -> List[str]:

# create a dict of headers to make it easy to find keys
headers = {
k.decode("utf-8"): v.decode("utf-8")
k.decode("utf-8").lower(): v.decode("utf-8")
for (k, v) in message.get("headers", ())
}

Expand Down Expand Up @@ -405,6 +405,10 @@ async def wrapped_send(message: Message) -> None:
await self.app(scope, receive, wrapped_send)
except Exception as e:
status_code = 500

# during an unhandled exception, populate response labels with empty strings.
response_labels = self._response_label_values({})

exception = e
finally:
# Decrement 'requests_in_progress' gauge after response sent
Expand Down
42 changes: 41 additions & 1 deletion tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def httpstatus_response(request):
)

async def error(request):
raise HTTPException(status_code=500, detail="this is a test error")
raise HTTPException(status_code=500, detail="this is a test error", headers={"foo":"baz"})

app.add_route("/500", error)
app.add_route("/500/{test_param}", error)
Expand Down Expand Up @@ -804,6 +804,46 @@ def test_from_response_header(self, testapp):
in metrics
), metrics

def test_from_response_header_case_insensitive(self, testapp):
"""test with the library-provided from_response_header function with a capitalized header key."""
labels = {"foo": from_response_header("Foo"), "hello": "world"}
client = TestClient(testapp(labels=labels))
client.get("/200")
metrics = client.get("/metrics").content.decode()

assert (
"""starlette_requests_total{app_name="starlette",foo="baz",hello="world",method="GET",path="/200",status_code="200"} 1.0"""
in metrics
), metrics

def test_from_response_header_http_exception(self, testapp):
"""test from_response_header against an endpoint that raises an HTTPException"""
labels = {"foo": from_response_header("foo"), "hello": "world"}
client = TestClient(testapp(labels=labels))
client.get("/500")
metrics = client.get("/metrics").content.decode()

assert (
"""starlette_requests_total{app_name="starlette",foo="baz",hello="world",method="GET",path="/500",status_code="500"} 1.0"""
in metrics
), metrics

def test_from_response_header_unhandled_exception(self, testapp):
"""test from_response_header function against an endpoint that raises an unhandled exception"""
labels = {"foo": from_response_header("foo"), "hello": "world"}
client = TestClient(testapp(labels=labels))

# make the test call. This raises an error but will still populate metrics.
with pytest.raises(KeyError, match="value_error"):
client.get("/unhandled")

metrics = client.get("/metrics").content.decode()

assert (
"""starlette_requests_total{app_name="starlette",foo="",hello="world",method="GET",path="/unhandled",status_code="500"} 1.0"""
in metrics
), metrics

def test_from_response_header_default(self, testapp):
"""test with the library-provided from_response_header function, with a missing header
(testing the default value)"""
Expand Down

0 comments on commit 8fafd31

Please sign in to comment.