diff --git a/apitally/client/request_logging.py b/apitally/client/request_logging.py index 6954b7a..a0f1537 100644 --- a/apitally/client/request_logging.py +++ b/apitally/client/request_logging.py @@ -42,6 +42,7 @@ class RequestDict(TypedDict): path: Optional[str] url: str headers: Dict[str, str] + size: Optional[int] consumer: Optional[str] @@ -49,7 +50,7 @@ class ResponseDict(TypedDict): status_code: int response_time: float headers: Dict[str, str] - size: int | None + size: Optional[int] class TempGzipFile: diff --git a/apitally/common.py b/apitally/common.py index ab66f3e..d0133df 100644 --- a/apitally/common.py +++ b/apitally/common.py @@ -1,6 +1,15 @@ import sys from importlib.metadata import PackageNotFoundError, version -from typing import Dict, Optional +from typing import Dict, Optional, Union + + +def parse_int(x: Union[str, int, None]) -> Optional[int]: + if x is None: + return None + try: + return int(x) + except ValueError: + return None def get_versions(*packages, app_version: Optional[str] = None) -> Dict[str, str]: diff --git a/apitally/django.py b/apitally/django.py index 194b9b5..62002f8 100644 --- a/apitally/django.py +++ b/apitally/django.py @@ -17,7 +17,7 @@ from apitally.client.consumers import Consumer as ApitallyConsumer from apitally.client.logging import get_logger from apitally.client.request_logging import RequestLoggingConfig -from apitally.common import get_versions +from apitally.common import get_versions, parse_int if TYPE_CHECKING: @@ -98,10 +98,11 @@ def __call__(self, request: HttpRequest) -> HttpResponse: response = self.get_response(request) response_time = time.perf_counter() - start_time response_size = ( - _to_int(response["Content-Length"]) + parse_int(response["Content-Length"]) if response.has_header("Content-Length") else (len(response.content) if not response.streaming else None) ) + request_size = parse_int(request.headers.get("Content-Length")) path = self.get_path(request) try: @@ -120,7 +121,7 @@ def __call__(self, request: HttpRequest) -> HttpResponse: path=path, status_code=response.status_code, response_time=response_time, - request_size=request.headers.get("Content-Length"), + request_size=request_size, response_size=response_size, ) except Exception: # pragma: no cover @@ -163,6 +164,7 @@ def __call__(self, request: HttpRequest) -> HttpResponse: "path": path, "url": request.build_absolute_uri(), "headers": dict(request.headers), + "size": request_size, "consumer": consumer_identifier, }, response={ @@ -364,12 +366,3 @@ def _check_import(name: str) -> bool: return True except ImportError: return False - - -def _to_int(x: Union[str, int, None]) -> Optional[int]: - if x is None: - return None - try: - return int(x) - except ValueError: - return None diff --git a/apitally/flask.py b/apitally/flask.py index 8b6e99d..4eaf120 100644 --- a/apitally/flask.py +++ b/apitally/flask.py @@ -124,6 +124,7 @@ def add_request( "path": path, "url": request.url, "headers": dict(request.headers), + "size": request.content_length, "consumer": consumer_identifier, }, response={ diff --git a/apitally/litestar.py b/apitally/litestar.py index 2f7ff21..347d9bd 100644 --- a/apitally/litestar.py +++ b/apitally/litestar.py @@ -16,7 +16,7 @@ from apitally.client.client_asyncio import ApitallyClient from apitally.client.consumers import Consumer as ApitallyConsumer from apitally.client.request_logging import RequestLoggingConfig -from apitally.common import get_versions +from apitally.common import get_versions, parse_int __all__ = ["ApitallyPlugin", "ApitallyConsumer", "RequestLoggingConfig"] @@ -122,13 +122,15 @@ def add_request( response_time: float, response_headers: Headers, response_body: bytes, - response_size: int = 0, + response_size: Optional[int] = None, ) -> None: if response_status < 100: return # pragma: no cover path = self.get_path(request) if self.filter_path(path): return + request_size = parse_int(request.headers.get("Content-Length")) + response_size = response_size or parse_int(response_headers.get("Content-Length")) consumer = self.get_consumer(request) consumer_identifier = consumer.identifier if consumer else None @@ -141,8 +143,8 @@ def add_request( path=path, status_code=response_status, response_time=response_time, - request_size=request.headers.get("Content-Length"), - response_size=response_size or response_headers.get("Content-Length"), + request_size=request_size, + response_size=response_size, ) if response_status == 400 and response_body and len(response_body) < 4096: @@ -186,6 +188,7 @@ def add_request( "path": path, "url": str(request.url), "headers": dict(request.headers), + "size": request_size, "consumer": consumer_identifier, }, response={ diff --git a/apitally/starlette.py b/apitally/starlette.py index d549179..55eeb99 100644 --- a/apitally/starlette.py +++ b/apitally/starlette.py @@ -18,7 +18,7 @@ from apitally.client.client_asyncio import ApitallyClient from apitally.client.consumers import Consumer as ApitallyConsumer from apitally.client.request_logging import RequestLoggingConfig -from apitally.common import get_versions +from apitally.common import get_versions, parse_int __all__ = ["ApitallyMiddleware", "ApitallyConsumer", "RequestLoggingConfig"] @@ -117,10 +117,13 @@ def add_request( response_time: float, response_headers: Headers, response_body: bytes, - response_size: int = 0, + response_size: Optional[int] = None, exception: Optional[BaseException] = None, ) -> None: path = self.get_path(request) + request_size = parse_int(request.headers.get("Content-Length")) + response_size = response_size or parse_int(response_headers.get("Content-Length")) + consumer = self.get_consumer(request) consumer_identifier = consumer.identifier if consumer else None self.client.consumer_registry.add_or_update_consumer(consumer) @@ -134,8 +137,8 @@ def add_request( path=path, status_code=response_status, response_time=response_time, - request_size=request.headers.get("Content-Length"), - response_size=response_size or response_headers.get("Content-Length"), + request_size=request_size, + response_size=response_size, ) if response_status == 422 and response_body and response_headers.get("Content-Type") == "application/json": with contextlib.suppress(json.JSONDecodeError): @@ -163,6 +166,7 @@ def add_request( "path": path, "url": str(request.url), "headers": dict(request.headers), + "size": request_size, "consumer": consumer_identifier, }, response={ diff --git a/tests/test_client_request_logging.py b/tests/test_client_request_logging.py index 7a55f88..bc71e89 100644 --- a/tests/test_client_request_logging.py +++ b/tests/test_client_request_logging.py @@ -14,6 +14,8 @@ def test_request_logger(): "path": "/test", "url": "http://localhost:8000/test?foo=bar", "headers": {"Accept": "application/json"}, + "size": 100, + "consumer": "test", } response: ResponseDict = { "status_code": 200,