Skip to content

Commit d51ce2c

Browse files
authored
Merge pull request #76 from Lancetnik/main
refactor: little LoggingMiddleware changes to save few processor ticks
2 parents 854a638 + 1a6bf19 commit d51ce2c

File tree

3 files changed

+42
-15
lines changed

3 files changed

+42
-15
lines changed

microbootstrap/middlewares/fastapi.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,37 @@
66
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
77

88
from microbootstrap.instruments.logging_instrument import fill_log_message
9+
from .utils import optimize_exclude_paths
910

1011

1112
def build_fastapi_logging_middleware(
1213
exclude_endpoints: typing.Iterable[str],
1314
) -> type[BaseHTTPMiddleware]:
15+
endpoints_to_ignore: typing.Collection[str] = optimize_exclude_paths(exclude_endpoints)
16+
1417
class FastAPILoggingMiddleware(BaseHTTPMiddleware):
1518
async def dispatch(
1619
self,
1720
request: fastapi.Request,
1821
call_next: RequestResponseEndpoint,
1922
) -> fastapi.Response:
2023
request_path: typing.Final = request.url.path.removesuffix("/")
21-
should_log: typing.Final = not any(
22-
exclude_endpoint == request_path for exclude_endpoint in exclude_endpoints
23-
)
24+
25+
if request_path in endpoints_to_ignore:
26+
return await call_next(request)
27+
2428
start_time: typing.Final = time.perf_counter_ns()
2529
try:
2630
response = await call_next(request)
2731
except Exception: # noqa: BLE001
2832
response = fastapi.Response(status_code=500)
2933

30-
if should_log:
31-
fill_log_message(
32-
"exception" if response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR else "info",
33-
request,
34-
response.status_code,
35-
start_time,
36-
)
34+
fill_log_message(
35+
"exception" if response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR else "info",
36+
request,
37+
response.status_code,
38+
start_time,
39+
)
3740
return response
3841

3942
return FastAPILoggingMiddleware

microbootstrap/middlewares/litestar.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
from litestar.status_codes import HTTP_500_INTERNAL_SERVER_ERROR
99

1010
from microbootstrap.instruments.logging_instrument import fill_log_message
11+
from .utils import optimize_exclude_paths
1112

1213

1314
def build_litestar_logging_middleware(
1415
exclude_endpoints: typing.Iterable[str],
1516
) -> type[MiddlewareProtocol]:
17+
endpoints_to_ignore: typing.Collection[str] = optimize_exclude_paths(exclude_endpoints)
18+
1619
class LitestarLoggingMiddleware(MiddlewareProtocol):
1720
def __init__(self, app: litestar.types.ASGIApp) -> None:
1821
self.app = app
@@ -24,14 +27,20 @@ async def __call__(
2427
send_function: litestar.types.Send,
2528
) -> None:
2629
request: typing.Final[litestar.Request] = litestar.Request(request_scope) # type: ignore[type-arg]
30+
31+
request_path = request.url.path.removesuffix("/")
32+
33+
if request_path in endpoints_to_ignore:
34+
await self.app(request_scope, receive, send_function)
35+
return
36+
2737
start_time: typing.Final[int] = time.perf_counter_ns()
2838

2939
async def log_message_wrapper(message: litestar.types.Message) -> None:
30-
request_path = request.url.path.removesuffix("/")
31-
should_log: typing.Final = not any(one_endpoint == request_path for one_endpoint in exclude_endpoints)
32-
if message["type"] == "http.response.start" and should_log:
33-
log_level: str = "info" if message["status"] < HTTP_500_INTERNAL_SERVER_ERROR else "exception"
34-
fill_log_message(log_level, request, message["status"], start_time)
40+
if message["type"] == "http.response.start":
41+
status = message["status"]
42+
log_level: str = "info" if status < HTTP_500_INTERNAL_SERVER_ERROR else "exception"
43+
fill_log_message(log_level, request, status, start_time)
3544

3645
await send_function(message)
3746

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import typing
2+
3+
4+
def optimize_exclude_paths(
5+
exclude_endpoints: typing.Iterable[str],
6+
) -> typing.Collection[str]:
7+
# `in` operator is faster for tuples than for lists
8+
endpoints_to_ignore: typing.Collection[str] = tuple(exclude_endpoints)
9+
10+
# 10 is just an empirical value, based of measuring the performance
11+
# iterating over a tuple of <10 elements is faster than hashing
12+
if len(endpoints_to_ignore) >= 10: # noqa: PLR2004
13+
endpoints_to_ignore = set(endpoints_to_ignore)
14+
15+
return endpoints_to_ignore

0 commit comments

Comments
 (0)