apitally 0.14.1__py3-none-any.whl → 0.14.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apitally/client/request_logging.py +20 -1
- apitally/starlette.py +12 -6
- {apitally-0.14.1.dist-info → apitally-0.14.3.dist-info}/METADATA +6 -5
- {apitally-0.14.1.dist-info → apitally-0.14.3.dist-info}/RECORD +6 -6
- {apitally-0.14.1.dist-info → apitally-0.14.3.dist-info}/WHEEL +1 -1
- {apitally-0.14.1.dist-info → apitally-0.14.3.dist-info}/licenses/LICENSE +0 -0
@@ -35,6 +35,12 @@ EXCLUDE_PATH_PATTERNS = [
|
|
35
35
|
r"/ready$",
|
36
36
|
r"/live$",
|
37
37
|
]
|
38
|
+
EXCLUDE_USER_AGENT_PATTERNS = [
|
39
|
+
r"health[_- ]?check",
|
40
|
+
r"microsoft-azure-application-lb",
|
41
|
+
r"googlehc",
|
42
|
+
r"kube-probe",
|
43
|
+
]
|
38
44
|
MASK_QUERY_PARAM_PATTERNS = [
|
39
45
|
r"auth",
|
40
46
|
r"api-?key",
|
@@ -162,7 +168,12 @@ class RequestLogger:
|
|
162
168
|
if not self.enabled or self.suspend_until is not None:
|
163
169
|
return
|
164
170
|
parsed_url = urlparse(request["url"])
|
165
|
-
|
171
|
+
user_agent = self._get_user_agent(request["headers"])
|
172
|
+
if (
|
173
|
+
self._should_exclude_path(request["path"] or parsed_url.path)
|
174
|
+
or self._should_exclude_user_agent(user_agent)
|
175
|
+
or self._should_exclude(request, response)
|
176
|
+
):
|
166
177
|
return
|
167
178
|
|
168
179
|
query = self._mask_query_params(parsed_url.query) if self.config.log_query_params else ""
|
@@ -271,6 +282,10 @@ class RequestLogger:
|
|
271
282
|
patterns = self.config.exclude_paths + EXCLUDE_PATH_PATTERNS
|
272
283
|
return self._match_patterns(url_path, patterns)
|
273
284
|
|
285
|
+
@lru_cache(maxsize=1000)
|
286
|
+
def _should_exclude_user_agent(self, user_agent: Optional[str]) -> bool:
|
287
|
+
return self._match_patterns(user_agent, EXCLUDE_USER_AGENT_PATTERNS) if user_agent is not None else False
|
288
|
+
|
274
289
|
def _mask_query_params(self, query: str) -> str:
|
275
290
|
query_params = parse_qsl(query)
|
276
291
|
masked_query_params = [(k, v if not self._should_mask_query_param(k) else MASKED) for k, v in query_params]
|
@@ -302,6 +317,10 @@ class RequestLogger:
|
|
302
317
|
content_type = next((v for k, v in headers if k.lower() == "content-type"), None)
|
303
318
|
return content_type is not None and any(content_type.startswith(t) for t in ALLOWED_CONTENT_TYPES)
|
304
319
|
|
320
|
+
@staticmethod
|
321
|
+
def _get_user_agent(headers: List[Tuple[str, str]]) -> Optional[str]:
|
322
|
+
return next((v for k, v in headers if k.lower() == "user-agent"), None)
|
323
|
+
|
305
324
|
|
306
325
|
def _check_writable_fs() -> bool:
|
307
326
|
try:
|
apitally/starlette.py
CHANGED
@@ -222,12 +222,18 @@ class ApitallyMiddleware:
|
|
222
222
|
},
|
223
223
|
)
|
224
224
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
if
|
230
|
-
|
225
|
+
def get_path(self, request: Request, routes: Optional[list[BaseRoute]] = None) -> Optional[str]:
|
226
|
+
if routes is None:
|
227
|
+
routes = request.app.routes
|
228
|
+
for route in routes:
|
229
|
+
if hasattr(route, "routes"):
|
230
|
+
path = self.get_path(request, routes=route.routes)
|
231
|
+
if path is not None:
|
232
|
+
return path
|
233
|
+
elif hasattr(route, "path"):
|
234
|
+
match, _ = route.matches(request.scope)
|
235
|
+
if match == Match.FULL:
|
236
|
+
return request.scope.get("root_path", "") + route.path
|
231
237
|
return None
|
232
238
|
|
233
239
|
def get_consumer(self, request: Request) -> Optional[ApitallyConsumer]:
|
@@ -1,12 +1,13 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: apitally
|
3
|
-
Version: 0.14.
|
3
|
+
Version: 0.14.3
|
4
4
|
Summary: Simple API monitoring & analytics for REST APIs built with FastAPI, Flask, Django, Starlette and Litestar.
|
5
5
|
Project-URL: Homepage, https://apitally.io
|
6
6
|
Project-URL: Documentation, https://docs.apitally.io
|
7
7
|
Project-URL: Repository, https://github.com/apitally/apitally-py
|
8
8
|
Author-email: Apitally <hello@apitally.io>
|
9
9
|
License: MIT License
|
10
|
+
License-File: LICENSE
|
10
11
|
Classifier: Development Status :: 5 - Production/Stable
|
11
12
|
Classifier: Environment :: Web Environment
|
12
13
|
Classifier: Framework :: Django
|
@@ -68,9 +69,9 @@ Description-Content-Type: text/markdown
|
|
68
69
|
</picture>
|
69
70
|
</p>
|
70
71
|
|
71
|
-
<p align="center"><b>
|
72
|
+
<p align="center"><b>Analytics, logging & monitoring for REST APIs.</b></p>
|
72
73
|
|
73
|
-
<p align="center"><i>Apitally
|
74
|
+
<p align="center"><i>Apitally helps you understand how your APIs are being used and alerts you when things go wrong.<br>It's super easy to use and designed to protect your data privacy.</i></p>
|
74
75
|
|
75
76
|
<p align="center">🔗 <b><a href="https://apitally.io" target="_blank">apitally.io</a></b></p>
|
76
77
|
|
@@ -100,7 +101,7 @@ the 📚 [documentation](https://docs.apitally.io).
|
|
100
101
|
## Key features
|
101
102
|
|
102
103
|
- Middleware for different frameworks to capture metadata about API endpoints,
|
103
|
-
requests and responses
|
104
|
+
requests and responses
|
104
105
|
- Non-blocking clients that aggregate and send captured data to Apitally in
|
105
106
|
regular intervals
|
106
107
|
|
@@ -7,18 +7,18 @@ apitally/fastapi.py,sha256=IfKfgsmIY8_AtnuMTW2sW4qnkya61CAE2vBoIpcc9tk,169
|
|
7
7
|
apitally/flask.py,sha256=Th5LsMsTKkWERPrKfSWPhzrp99tg0pDtKXgtlVLx3eo,9279
|
8
8
|
apitally/litestar.py,sha256=hAH2-OVVXBDVY8LopfIGv30yYwi-71tSEsKd6648CYc,13098
|
9
9
|
apitally/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
apitally/starlette.py,sha256=
|
10
|
+
apitally/starlette.py,sha256=VaT4-QVSYC0YX1U5kVI-dGROEd64IbjYU5lx5N16yf8,12852
|
11
11
|
apitally/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
apitally/client/client_asyncio.py,sha256=lRvVKFU6eiapJnB9WrRq6Nuadx-n8NCKwQg-da1vPSM,7064
|
13
13
|
apitally/client/client_base.py,sha256=w5AXAbg3hw5Qds5rovCZFtePB9bHNcJsr9l7kDgbroc,3733
|
14
14
|
apitally/client/client_threading.py,sha256=MbytG8EopF84nmr5ShAZaq-VviSXYnBfBl7cRFRe1Kg,7479
|
15
15
|
apitally/client/consumers.py,sha256=w_AFQhVgdtJVt7pVySBvSZwQg-2JVqmD2JQtVBoMkus,2626
|
16
16
|
apitally/client/logging.py,sha256=QMsKIIAFo92PNBUleeTgsrsQa7SEal-oJa1oOHUr1wI,507
|
17
|
-
apitally/client/request_logging.py,sha256=
|
17
|
+
apitally/client/request_logging.py,sha256=5i7Gv4yP7iq4tBgw-ppkhlZd_OwMc719ZvWEm16TCvg,13047
|
18
18
|
apitally/client/requests.py,sha256=RdJyvIqQGVHvS-wjpAPUwcO7byOJ6jO8dYqNTU2Furg,3685
|
19
19
|
apitally/client/server_errors.py,sha256=axEhOxqV5SWjk0QCZTLVv2UMIaTfqPc81Typ4DXt66A,4646
|
20
20
|
apitally/client/validation_errors.py,sha256=6G8WYWFgJs9VH9swvkPXJGuOJgymj5ooWA9OwjUTbuM,1964
|
21
|
-
apitally-0.14.
|
22
|
-
apitally-0.14.
|
23
|
-
apitally-0.14.
|
24
|
-
apitally-0.14.
|
21
|
+
apitally-0.14.3.dist-info/METADATA,sha256=ASnl8PEaJIOpTrMIIzs13F9T5jrnJ0I2gHTOnXEvPiU,7570
|
22
|
+
apitally-0.14.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
23
|
+
apitally-0.14.3.dist-info/licenses/LICENSE,sha256=vbLzC-4TddtXX-_AFEBKMYWRlxC_MN0g66QhPxo8PgY,1065
|
24
|
+
apitally-0.14.3.dist-info/RECORD,,
|
File without changes
|