Skip to content

Commit 233b92f

Browse files
committed
Add posibility to define ecludes from logging
1 parent 3e231ab commit 233b92f

File tree

3 files changed

+96
-15
lines changed

3 files changed

+96
-15
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ app.include_router(build_default_route(ingress_base_path=config.ingress_base_pat
3737
Extends the asgi-logger and adds a log entry for received requests.
3838
Furthermore the requests are filtered, so that health checks don't spam the logs.
3939

40-
For requests to be filtered, they need to have the header "healthcheck" with one of these values:
41-
"livenessprobe", "readinessprobe", "startupprobe", "prtg"
40+
For requests to be filtered it is possible to define substrings of the path with the optional
41+
parameter "excluded_pathes". (it can also be parts from the middle as it is a contains search)
4242

4343
```python
4444
from sag_py_web_common.filtered_access_logger import FilteredAccessLoggerMiddleware
@@ -49,6 +49,7 @@ app.add_middleware(
4949
FilteredAccessLoggerMiddleware,
5050
format="Completed: %(R)s - %(st)s - %(L)s",
5151
logger=logging.getLogger("access"),
52+
excluded_pathes=["pathPart/partOne", "pathPart/partTwo"], # optional
5253
)
5354
```
5455

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
1-
from typing import Dict
1+
import logging
2+
from typing import List, Union
23

3-
from asgi_logger.middleware import AccessInfo, AccessLogAtoms, AccessLoggerMiddleware
4-
from asgiref.typing import ASGIReceiveCallable, ASGISendCallable, HTTPScope
4+
from asgi_logger.middleware import (AccessInfo, AccessLogAtoms,
5+
AccessLoggerMiddleware)
6+
from asgiref.typing import (ASGI3Application, ASGIReceiveCallable,
7+
ASGISendCallable, HTTPScope)
58

69

710
class FilteredAccessLoggerMiddleware(AccessLoggerMiddleware):
811
"""The lib asgi-logger wrapped to exclude prtg and health checks from being logged
912
Furthermore it adds logging of the incoming requests
1013
"""
1114

15+
def __init__(
16+
self,
17+
app: ASGI3Application,
18+
format: Union[str, None],
19+
logger: Union[logging.Logger, None],
20+
excluded_pathes: Union[List[str], None]
21+
) -> None:
22+
super().__init__(app, format, logger)
23+
self.excluded_pathes = excluded_pathes or []
24+
1225
async def __call__(self, scope: HTTPScope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
1326
if self._should_log(scope):
1427
self.logger.info("Received: %s %s", scope["method"], scope["path"])
@@ -21,13 +34,13 @@ def log(self, scope: HTTPScope, info: AccessInfo) -> None:
2134
self.logger.info(self.format, AccessLogAtoms(scope, info), extra=extra_args)
2235

2336
def _should_log(self, scope: HTTPScope) -> bool:
24-
return scope["type"] == "http" and not self._has_health_check_header(scope)
25-
26-
def _has_health_check_header(self, scope: HTTPScope) -> bool:
27-
header_dict: Dict[bytes, bytes] = dict(scope["headers"])
28-
return b"healthcheck" in header_dict and header_dict[b"healthcheck"] in {
29-
b"livenessprobe",
30-
b"readinessprobe",
31-
b"startupprobe",
32-
b"prtg",
33-
}
37+
return scope["type"] == "http" \
38+
and not FilteredAccessLoggerMiddleware._is_excluded_path(scope, self.excluded_pathes)
39+
40+
@staticmethod
41+
def _is_excluded_path(scope: HTTPScope, excluded_pathes: List[str]) -> bool:
42+
if not excluded_pathes:
43+
return False
44+
45+
path: str = str(scope["path"])
46+
return any(excluded in path for excluded in excluded_pathes)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from typing import List
2+
3+
import pytest
4+
5+
from sag_py_web_common.filtered_access_logger import \
6+
FilteredAccessLoggerMiddleware
7+
8+
9+
@pytest.mark.parametrize("path,expected", [
10+
("/api/maintain/serviceStatus", True),
11+
("/api/maintain/serviceStatusKubernetes", True),
12+
("/api/maintain/serviceStatusPrtg", True),
13+
("/maintain/serviceStatus", True),
14+
("/maintain/serviceStatusKubernetes", True),
15+
("/maintain/serviceStatusPrtg", True),
16+
("/health/serviceStatus", True),
17+
("/health/serviceStatusKubernetes", True),
18+
("/health/serviceStatusPrtg", True),
19+
("/otherEndpoint/serviceStatus", False),
20+
("/serviceStatus", False),
21+
("/my/other/endpoint", False),
22+
("/", False)
23+
])
24+
def test_is_excluded_path_with_ignore_list(path: str, expected: bool) -> None:
25+
# Arrange
26+
excluded_pathes = ["maintain/serviceStatus", "health/serviceStatus"]
27+
scope = {"path": path}
28+
29+
# Act
30+
actual = FilteredAccessLoggerMiddleware._is_excluded_path(scope, excluded_pathes) # type: ignore
31+
32+
# Assert
33+
assert actual == expected
34+
35+
36+
@pytest.mark.parametrize("path,expected", [
37+
("/serviceStatus", False),
38+
("/my/other/endpoint", False),
39+
("/", False)
40+
])
41+
def test_is_excluded_path_without_ignore_list(path: str, expected: bool) -> None:
42+
# Arrange
43+
excluded_pathes = None
44+
scope = {"path": path}
45+
46+
# Act
47+
actual = FilteredAccessLoggerMiddleware._is_excluded_path(scope, excluded_pathes) # type: ignore
48+
49+
# Assert
50+
assert actual == expected
51+
52+
53+
@pytest.mark.parametrize("path,expected", [
54+
("/serviceStatus", False),
55+
("/my/other/endpoint", False),
56+
("/", False)
57+
])
58+
def test_is_excluded_path_with_empty_ignore_list(path: str, expected: bool) -> None:
59+
# Arrange
60+
excluded_pathes: List[str] = []
61+
scope = {"path": path}
62+
63+
# Act
64+
actual = FilteredAccessLoggerMiddleware._is_excluded_path(scope, excluded_pathes) # type: ignore
65+
66+
# Assert
67+
assert actual == expected

0 commit comments

Comments
 (0)