beans-logging 5.0.0__tar.gz → 6.0.0__tar.gz

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.
Files changed (30) hide show
  1. {beans_logging-5.0.0 → beans_logging-6.0.0}/PKG-INFO +9 -152
  2. {beans_logging-5.0.0 → beans_logging-6.0.0}/README.md +5 -150
  3. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/__version__.py +1 -1
  4. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging.egg-info/PKG-INFO +9 -152
  5. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging.egg-info/SOURCES.txt +0 -5
  6. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging.egg-info/requires.txt +3 -0
  7. {beans_logging-5.0.0 → beans_logging-6.0.0}/setup.py +1 -0
  8. beans_logging-5.0.0/beans_logging/fastapi/__init__.py +0 -6
  9. beans_logging-5.0.0/beans_logging/fastapi/_filters.py +0 -22
  10. beans_logging-5.0.0/beans_logging/fastapi/_formats.py +0 -62
  11. beans_logging-5.0.0/beans_logging/fastapi/_handlers.py +0 -79
  12. beans_logging-5.0.0/beans_logging/fastapi/_middlewares.py +0 -262
  13. {beans_logging-5.0.0 → beans_logging-6.0.0}/LICENSE.txt +0 -0
  14. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/__init__.py +0 -0
  15. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/_base.py +0 -0
  16. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/_consts.py +0 -0
  17. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/_handlers.py +0 -0
  18. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/_utils.py +0 -0
  19. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/auto.py +0 -0
  20. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/filters.py +0 -0
  21. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/formats.py +0 -0
  22. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/rotation.py +0 -0
  23. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/schemas.py +0 -0
  24. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging/sinks.py +0 -0
  25. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging.egg-info/dependency_links.txt +0 -0
  26. {beans_logging-5.0.0 → beans_logging-6.0.0}/beans_logging.egg-info/top_level.txt +0 -0
  27. {beans_logging-5.0.0 → beans_logging-6.0.0}/setup.cfg +0 -0
  28. {beans_logging-5.0.0 → beans_logging-6.0.0}/tests/__init__.py +0 -0
  29. {beans_logging-5.0.0 → beans_logging-6.0.0}/tests/conftest.py +0 -0
  30. {beans_logging-5.0.0 → beans_logging-6.0.0}/tests/test_beans_logging.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: beans_logging
3
- Version: 5.0.0
3
+ Version: 6.0.0
4
4
  Summary: 'beans_logging' is a python package for simple logger and easily managing logging modules. It is a Loguru based custom logging package for python projects.
5
5
  Home-page: https://github.com/bybatkhuu/module.python-logging
6
- Download-URL: https://github.com/bybatkhuu/module.python-logging/archive/v5.0.0.tar.gz
6
+ Download-URL: https://github.com/bybatkhuu/module.python-logging/archive/v6.0.0.tar.gz
7
7
  Author: Batkhuu Byambajav
8
8
  Author-email: batkhuu10@gmail.com
9
9
  License: MIT
@@ -22,6 +22,8 @@ License-File: LICENSE.txt
22
22
  Requires-Dist: PyYAML<7.0,>=6.0
23
23
  Requires-Dist: pydantic!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.10.0
24
24
  Requires-Dist: loguru<1.0.0,>=0.7.2
25
+ Provides-Extra: fastapi
26
+ Requires-Dist: beans-logging-fastapi<2.0.0,>=1.0.0; extra == "fastapi"
25
27
 
26
28
  # beans_logging
27
29
 
@@ -47,7 +49,6 @@ It is a `Loguru` based custom logging package for python projects.
47
49
  - Custom logging **formats**
48
50
  - **Multiprocess** compatibility (Linux, macOS - 'fork')
49
51
  - Add custom **handlers**
50
- - **FastAPI** HTTP access logging **middleware**
51
52
  - **Base** logging module
52
53
  - Support **Pydantic-v1** and **Pydantic-v2**
53
54
 
@@ -236,157 +237,12 @@ Traceback (most recent call last):
236
237
  ZeroDivisionError: division by zero
237
238
  ```
238
239
 
239
- ### **Advanced (FastAPI)**
240
+ ### **FastAPI**
240
241
 
241
- [**`configs/logger.yml`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/configs/logger.yml):
242
+ Checkout `beans_logging_fastapi` package: <https://github.com/bybatkhuu/module.fastapi-logging>
242
243
 
243
- ```yaml
244
- logger:
245
- app_name: "fastapi-app"
246
- level: "TRACE"
247
- use_diagnose: false
248
- stream:
249
- use_color: true
250
- use_icon: false
251
- format_str: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{level_short:<5}</level> | <w>{name}:{line}</w>]: <level>{message}</level>"
252
- std_handler:
253
- enabled: true
254
- file:
255
- logs_dir: "./logs"
256
- rotate_size: 10000000 # 10MB
257
- rotate_time: "00:00:00"
258
- backup_count: 90
259
- log_handlers:
260
- enabled: true
261
- format_str: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {level_short:<5} | {name}:{line}]: {message}"
262
- log_path: "{app_name}.std.all.log"
263
- err_path: "{app_name}.std.err.log"
264
- json_handlers:
265
- enabled: true
266
- use_custom: false
267
- log_path: "json/{app_name}.json.all.log"
268
- err_path: "json/{app_name}.json.err.log"
269
- intercept:
270
- auto_load:
271
- enabled: true
272
- only_base: false
273
- ignore_modules: []
274
- include_modules: []
275
- mute_modules: ["uvicorn.access", "uvicorn.error"]
276
- extra:
277
- http_std_debug_format: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
278
- http_std_msg_format: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" {status_code} {content_length}B {response_time}ms'
279
- http_file_enabled: true
280
- http_log_path: "http/{app_name}.http.access.log"
281
- http_err_path: "http/{app_name}.http.err.log"
282
- http_json_enabled: true
283
- http_json_path: "json.http/{app_name}.json.http.access.log"
284
- http_json_err_path: "json.http/{app_name}.json.http.err.log"
285
- ```
286
-
287
- [**`.env`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/.env):
288
-
289
- ```sh
290
- ENV=development
291
- DEBUG=true
292
- ```
293
-
294
- [**`logger.py`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/logger.py):
295
-
296
- ```python
297
- from beans_logging import Logger, LoggerLoader
298
- from beans_logging.fastapi import add_http_file_handler, add_http_file_json_handler
299
-
300
-
301
- logger_loader = LoggerLoader()
302
- logger: Logger = logger_loader.load()
303
-
304
- if logger_loader.config.extra.http_file_enabled:
305
- add_http_file_handler(
306
- logger_loader=logger_loader,
307
- log_path=logger_loader.config.extra.http_log_path,
308
- err_path=logger_loader.config.extra.http_err_path,
309
- )
310
-
311
- if logger_loader.config.extra.http_json_enabled:
312
- add_http_file_json_handler(
313
- logger_loader=logger_loader,
314
- log_path=logger_loader.config.extra.http_json_path,
315
- err_path=logger_loader.config.extra.http_json_err_path,
316
- )
317
- ```
318
-
319
- [**`main.py`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/main.py):
320
-
321
- ```python
322
- from typing import Union
323
- from contextlib import asynccontextmanager
324
-
325
- from dotenv import load_dotenv
326
- from fastapi import FastAPI, HTTPException
327
- from fastapi.responses import RedirectResponse
328
-
329
- load_dotenv()
330
-
331
- from beans_logging.fastapi import HttpAccessLogMiddleware
332
-
333
- from logger import logger, logger_loader
334
- from __version__ import __version__
335
-
336
-
337
- @asynccontextmanager
338
- async def lifespan(app: FastAPI):
339
- logger.info("Preparing to startup...")
340
- logger.success("Finished preparation to startup.")
341
- logger.info(f"API version: {__version__}")
342
-
343
- yield
344
- logger.info("Praparing to shutdown...")
345
- logger.success("Finished preparation to shutdown.")
346
-
347
- app = FastAPI(lifespan=lifespan, version=__version__)
348
- app.add_middleware(
349
- HttpAccessLogMiddleware,
350
- has_proxy_headers=True,
351
- debug_format=logger_loader.config.extra.http_std_debug_format,
352
- msg_format=logger_loader.config.extra.http_std_msg_format,
353
- )
354
-
355
- @app.get("/")
356
- def root():
357
- return {"Hello": "World"}
358
- ```
359
-
360
- Run the [**`examples/advanced`**](https://github.com/bybatkhuu/module.python-logging/tree/main/examples/advanced):
361
-
362
- ```sh
363
- cd ./examples/advanced
364
- # Install python dependencies for examples:
365
- pip install -r ./requirements.txt
366
-
367
- uvicorn main:app --host=0.0.0.0 --port=8000
368
- ```
369
-
370
- **Output**:
371
-
372
- ```txt
373
- [2023-09-01 00:00:00.000 +09:00 | TRACE | beans_logging._base:576]: Intercepted modules: ['watchfiles.watcher', 'dotenv', 'asyncio', 'dotenv.main', 'watchfiles.main', 'concurrent.futures', 'uvicorn', 'fastapi', 'concurrent', 'watchfiles']; Muted modules: ['uvicorn.access', 'uvicorn.error'];
374
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:76]: Started server process [17146]
375
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:46]: Waiting for application startup.
376
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:21]: Preparing to startup...
377
- [2023-09-01 00:00:00.000 +09:00 | OK | main:22]: Finished preparation to startup.
378
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:23]: API version: 0.0.1-000000
379
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:60]: Application startup complete.
380
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:218]: Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
381
- [2023-09-01 00:00:00.000 +09:00 | DEBUG | anyio._backends._asyncio:833]: [f635ebbc3f2348db9dcff681be1bd52a] 127.0.0.1 - "GET / HTTP/1.1"
382
- [2023-09-01 00:00:00.000 +09:00 | OK | anyio._backends._asyncio:833]: [f635ebbc3f2348db9dcff681be1bd52a] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 0.7ms
383
- ^C[2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:264]: Shutting down
384
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:65]: Waiting for application shutdown.
385
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:26]: Praparing to shutdown...
386
- [2023-09-01 00:00:00.000 +09:00 | OK | main:27]: Finished preparation to shutdown.
387
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
388
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:86]: Finished server process [17146]
389
- ```
244
+ - FastAPI HTTP access logging middleware
245
+ - Install with pip: `pip install -U beans-logging[fastapi]` or `pip install -U beans-logging-fastapi`
390
246
 
391
247
  ---
392
248
 
@@ -467,3 +323,4 @@ logger:
467
323
  - <https://github.com/Delgan/loguru>
468
324
  - <https://loguru.readthedocs.io/en/stable/api/logger.html>
469
325
  - <https://loguru.readthedocs.io/en/stable/resources/recipes.html>
326
+ - <https://github.com/bybatkhuu/module.fastapi-logging>
@@ -22,7 +22,6 @@ It is a `Loguru` based custom logging package for python projects.
22
22
  - Custom logging **formats**
23
23
  - **Multiprocess** compatibility (Linux, macOS - 'fork')
24
24
  - Add custom **handlers**
25
- - **FastAPI** HTTP access logging **middleware**
26
25
  - **Base** logging module
27
26
  - Support **Pydantic-v1** and **Pydantic-v2**
28
27
 
@@ -211,157 +210,12 @@ Traceback (most recent call last):
211
210
  ZeroDivisionError: division by zero
212
211
  ```
213
212
 
214
- ### **Advanced (FastAPI)**
213
+ ### **FastAPI**
215
214
 
216
- [**`configs/logger.yml`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/configs/logger.yml):
215
+ Checkout `beans_logging_fastapi` package: <https://github.com/bybatkhuu/module.fastapi-logging>
217
216
 
218
- ```yaml
219
- logger:
220
- app_name: "fastapi-app"
221
- level: "TRACE"
222
- use_diagnose: false
223
- stream:
224
- use_color: true
225
- use_icon: false
226
- format_str: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{level_short:<5}</level> | <w>{name}:{line}</w>]: <level>{message}</level>"
227
- std_handler:
228
- enabled: true
229
- file:
230
- logs_dir: "./logs"
231
- rotate_size: 10000000 # 10MB
232
- rotate_time: "00:00:00"
233
- backup_count: 90
234
- log_handlers:
235
- enabled: true
236
- format_str: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {level_short:<5} | {name}:{line}]: {message}"
237
- log_path: "{app_name}.std.all.log"
238
- err_path: "{app_name}.std.err.log"
239
- json_handlers:
240
- enabled: true
241
- use_custom: false
242
- log_path: "json/{app_name}.json.all.log"
243
- err_path: "json/{app_name}.json.err.log"
244
- intercept:
245
- auto_load:
246
- enabled: true
247
- only_base: false
248
- ignore_modules: []
249
- include_modules: []
250
- mute_modules: ["uvicorn.access", "uvicorn.error"]
251
- extra:
252
- http_std_debug_format: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
253
- http_std_msg_format: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" {status_code} {content_length}B {response_time}ms'
254
- http_file_enabled: true
255
- http_log_path: "http/{app_name}.http.access.log"
256
- http_err_path: "http/{app_name}.http.err.log"
257
- http_json_enabled: true
258
- http_json_path: "json.http/{app_name}.json.http.access.log"
259
- http_json_err_path: "json.http/{app_name}.json.http.err.log"
260
- ```
261
-
262
- [**`.env`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/.env):
263
-
264
- ```sh
265
- ENV=development
266
- DEBUG=true
267
- ```
268
-
269
- [**`logger.py`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/logger.py):
270
-
271
- ```python
272
- from beans_logging import Logger, LoggerLoader
273
- from beans_logging.fastapi import add_http_file_handler, add_http_file_json_handler
274
-
275
-
276
- logger_loader = LoggerLoader()
277
- logger: Logger = logger_loader.load()
278
-
279
- if logger_loader.config.extra.http_file_enabled:
280
- add_http_file_handler(
281
- logger_loader=logger_loader,
282
- log_path=logger_loader.config.extra.http_log_path,
283
- err_path=logger_loader.config.extra.http_err_path,
284
- )
285
-
286
- if logger_loader.config.extra.http_json_enabled:
287
- add_http_file_json_handler(
288
- logger_loader=logger_loader,
289
- log_path=logger_loader.config.extra.http_json_path,
290
- err_path=logger_loader.config.extra.http_json_err_path,
291
- )
292
- ```
293
-
294
- [**`main.py`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/main.py):
295
-
296
- ```python
297
- from typing import Union
298
- from contextlib import asynccontextmanager
299
-
300
- from dotenv import load_dotenv
301
- from fastapi import FastAPI, HTTPException
302
- from fastapi.responses import RedirectResponse
303
-
304
- load_dotenv()
305
-
306
- from beans_logging.fastapi import HttpAccessLogMiddleware
307
-
308
- from logger import logger, logger_loader
309
- from __version__ import __version__
310
-
311
-
312
- @asynccontextmanager
313
- async def lifespan(app: FastAPI):
314
- logger.info("Preparing to startup...")
315
- logger.success("Finished preparation to startup.")
316
- logger.info(f"API version: {__version__}")
317
-
318
- yield
319
- logger.info("Praparing to shutdown...")
320
- logger.success("Finished preparation to shutdown.")
321
-
322
- app = FastAPI(lifespan=lifespan, version=__version__)
323
- app.add_middleware(
324
- HttpAccessLogMiddleware,
325
- has_proxy_headers=True,
326
- debug_format=logger_loader.config.extra.http_std_debug_format,
327
- msg_format=logger_loader.config.extra.http_std_msg_format,
328
- )
329
-
330
- @app.get("/")
331
- def root():
332
- return {"Hello": "World"}
333
- ```
334
-
335
- Run the [**`examples/advanced`**](https://github.com/bybatkhuu/module.python-logging/tree/main/examples/advanced):
336
-
337
- ```sh
338
- cd ./examples/advanced
339
- # Install python dependencies for examples:
340
- pip install -r ./requirements.txt
341
-
342
- uvicorn main:app --host=0.0.0.0 --port=8000
343
- ```
344
-
345
- **Output**:
346
-
347
- ```txt
348
- [2023-09-01 00:00:00.000 +09:00 | TRACE | beans_logging._base:576]: Intercepted modules: ['watchfiles.watcher', 'dotenv', 'asyncio', 'dotenv.main', 'watchfiles.main', 'concurrent.futures', 'uvicorn', 'fastapi', 'concurrent', 'watchfiles']; Muted modules: ['uvicorn.access', 'uvicorn.error'];
349
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:76]: Started server process [17146]
350
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:46]: Waiting for application startup.
351
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:21]: Preparing to startup...
352
- [2023-09-01 00:00:00.000 +09:00 | OK | main:22]: Finished preparation to startup.
353
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:23]: API version: 0.0.1-000000
354
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:60]: Application startup complete.
355
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:218]: Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
356
- [2023-09-01 00:00:00.000 +09:00 | DEBUG | anyio._backends._asyncio:833]: [f635ebbc3f2348db9dcff681be1bd52a] 127.0.0.1 - "GET / HTTP/1.1"
357
- [2023-09-01 00:00:00.000 +09:00 | OK | anyio._backends._asyncio:833]: [f635ebbc3f2348db9dcff681be1bd52a] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 0.7ms
358
- ^C[2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:264]: Shutting down
359
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:65]: Waiting for application shutdown.
360
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:26]: Praparing to shutdown...
361
- [2023-09-01 00:00:00.000 +09:00 | OK | main:27]: Finished preparation to shutdown.
362
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
363
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:86]: Finished server process [17146]
364
- ```
217
+ - FastAPI HTTP access logging middleware
218
+ - Install with pip: `pip install -U beans-logging[fastapi]` or `pip install -U beans-logging-fastapi`
365
219
 
366
220
  ---
367
221
 
@@ -442,3 +296,4 @@ logger:
442
296
  - <https://github.com/Delgan/loguru>
443
297
  - <https://loguru.readthedocs.io/en/stable/api/logger.html>
444
298
  - <https://loguru.readthedocs.io/en/stable/resources/recipes.html>
299
+ - <https://github.com/bybatkhuu/module.fastapi-logging>
@@ -1,3 +1,3 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- __version__ = "5.0.0"
3
+ __version__ = "6.0.0"
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: beans-logging
3
- Version: 5.0.0
3
+ Version: 6.0.0
4
4
  Summary: 'beans_logging' is a python package for simple logger and easily managing logging modules. It is a Loguru based custom logging package for python projects.
5
5
  Home-page: https://github.com/bybatkhuu/module.python-logging
6
- Download-URL: https://github.com/bybatkhuu/module.python-logging/archive/v5.0.0.tar.gz
6
+ Download-URL: https://github.com/bybatkhuu/module.python-logging/archive/v6.0.0.tar.gz
7
7
  Author: Batkhuu Byambajav
8
8
  Author-email: batkhuu10@gmail.com
9
9
  License: MIT
@@ -22,6 +22,8 @@ License-File: LICENSE.txt
22
22
  Requires-Dist: PyYAML<7.0,>=6.0
23
23
  Requires-Dist: pydantic!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.10.0
24
24
  Requires-Dist: loguru<1.0.0,>=0.7.2
25
+ Provides-Extra: fastapi
26
+ Requires-Dist: beans-logging-fastapi<2.0.0,>=1.0.0; extra == "fastapi"
25
27
 
26
28
  # beans_logging
27
29
 
@@ -47,7 +49,6 @@ It is a `Loguru` based custom logging package for python projects.
47
49
  - Custom logging **formats**
48
50
  - **Multiprocess** compatibility (Linux, macOS - 'fork')
49
51
  - Add custom **handlers**
50
- - **FastAPI** HTTP access logging **middleware**
51
52
  - **Base** logging module
52
53
  - Support **Pydantic-v1** and **Pydantic-v2**
53
54
 
@@ -236,157 +237,12 @@ Traceback (most recent call last):
236
237
  ZeroDivisionError: division by zero
237
238
  ```
238
239
 
239
- ### **Advanced (FastAPI)**
240
+ ### **FastAPI**
240
241
 
241
- [**`configs/logger.yml`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/configs/logger.yml):
242
+ Checkout `beans_logging_fastapi` package: <https://github.com/bybatkhuu/module.fastapi-logging>
242
243
 
243
- ```yaml
244
- logger:
245
- app_name: "fastapi-app"
246
- level: "TRACE"
247
- use_diagnose: false
248
- stream:
249
- use_color: true
250
- use_icon: false
251
- format_str: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{level_short:<5}</level> | <w>{name}:{line}</w>]: <level>{message}</level>"
252
- std_handler:
253
- enabled: true
254
- file:
255
- logs_dir: "./logs"
256
- rotate_size: 10000000 # 10MB
257
- rotate_time: "00:00:00"
258
- backup_count: 90
259
- log_handlers:
260
- enabled: true
261
- format_str: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {level_short:<5} | {name}:{line}]: {message}"
262
- log_path: "{app_name}.std.all.log"
263
- err_path: "{app_name}.std.err.log"
264
- json_handlers:
265
- enabled: true
266
- use_custom: false
267
- log_path: "json/{app_name}.json.all.log"
268
- err_path: "json/{app_name}.json.err.log"
269
- intercept:
270
- auto_load:
271
- enabled: true
272
- only_base: false
273
- ignore_modules: []
274
- include_modules: []
275
- mute_modules: ["uvicorn.access", "uvicorn.error"]
276
- extra:
277
- http_std_debug_format: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
278
- http_std_msg_format: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" {status_code} {content_length}B {response_time}ms'
279
- http_file_enabled: true
280
- http_log_path: "http/{app_name}.http.access.log"
281
- http_err_path: "http/{app_name}.http.err.log"
282
- http_json_enabled: true
283
- http_json_path: "json.http/{app_name}.json.http.access.log"
284
- http_json_err_path: "json.http/{app_name}.json.http.err.log"
285
- ```
286
-
287
- [**`.env`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/.env):
288
-
289
- ```sh
290
- ENV=development
291
- DEBUG=true
292
- ```
293
-
294
- [**`logger.py`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/logger.py):
295
-
296
- ```python
297
- from beans_logging import Logger, LoggerLoader
298
- from beans_logging.fastapi import add_http_file_handler, add_http_file_json_handler
299
-
300
-
301
- logger_loader = LoggerLoader()
302
- logger: Logger = logger_loader.load()
303
-
304
- if logger_loader.config.extra.http_file_enabled:
305
- add_http_file_handler(
306
- logger_loader=logger_loader,
307
- log_path=logger_loader.config.extra.http_log_path,
308
- err_path=logger_loader.config.extra.http_err_path,
309
- )
310
-
311
- if logger_loader.config.extra.http_json_enabled:
312
- add_http_file_json_handler(
313
- logger_loader=logger_loader,
314
- log_path=logger_loader.config.extra.http_json_path,
315
- err_path=logger_loader.config.extra.http_json_err_path,
316
- )
317
- ```
318
-
319
- [**`main.py`**](https://github.com/bybatkhuu/module.python-logging/blob/main/examples/advanced/main.py):
320
-
321
- ```python
322
- from typing import Union
323
- from contextlib import asynccontextmanager
324
-
325
- from dotenv import load_dotenv
326
- from fastapi import FastAPI, HTTPException
327
- from fastapi.responses import RedirectResponse
328
-
329
- load_dotenv()
330
-
331
- from beans_logging.fastapi import HttpAccessLogMiddleware
332
-
333
- from logger import logger, logger_loader
334
- from __version__ import __version__
335
-
336
-
337
- @asynccontextmanager
338
- async def lifespan(app: FastAPI):
339
- logger.info("Preparing to startup...")
340
- logger.success("Finished preparation to startup.")
341
- logger.info(f"API version: {__version__}")
342
-
343
- yield
344
- logger.info("Praparing to shutdown...")
345
- logger.success("Finished preparation to shutdown.")
346
-
347
- app = FastAPI(lifespan=lifespan, version=__version__)
348
- app.add_middleware(
349
- HttpAccessLogMiddleware,
350
- has_proxy_headers=True,
351
- debug_format=logger_loader.config.extra.http_std_debug_format,
352
- msg_format=logger_loader.config.extra.http_std_msg_format,
353
- )
354
-
355
- @app.get("/")
356
- def root():
357
- return {"Hello": "World"}
358
- ```
359
-
360
- Run the [**`examples/advanced`**](https://github.com/bybatkhuu/module.python-logging/tree/main/examples/advanced):
361
-
362
- ```sh
363
- cd ./examples/advanced
364
- # Install python dependencies for examples:
365
- pip install -r ./requirements.txt
366
-
367
- uvicorn main:app --host=0.0.0.0 --port=8000
368
- ```
369
-
370
- **Output**:
371
-
372
- ```txt
373
- [2023-09-01 00:00:00.000 +09:00 | TRACE | beans_logging._base:576]: Intercepted modules: ['watchfiles.watcher', 'dotenv', 'asyncio', 'dotenv.main', 'watchfiles.main', 'concurrent.futures', 'uvicorn', 'fastapi', 'concurrent', 'watchfiles']; Muted modules: ['uvicorn.access', 'uvicorn.error'];
374
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:76]: Started server process [17146]
375
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:46]: Waiting for application startup.
376
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:21]: Preparing to startup...
377
- [2023-09-01 00:00:00.000 +09:00 | OK | main:22]: Finished preparation to startup.
378
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:23]: API version: 0.0.1-000000
379
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:60]: Application startup complete.
380
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:218]: Uvicorn running on http://0.0.0.0:9000 (Press CTRL+C to quit)
381
- [2023-09-01 00:00:00.000 +09:00 | DEBUG | anyio._backends._asyncio:833]: [f635ebbc3f2348db9dcff681be1bd52a] 127.0.0.1 - "GET / HTTP/1.1"
382
- [2023-09-01 00:00:00.000 +09:00 | OK | anyio._backends._asyncio:833]: [f635ebbc3f2348db9dcff681be1bd52a] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 0.7ms
383
- ^C[2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:264]: Shutting down
384
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:65]: Waiting for application shutdown.
385
- [2023-09-01 00:00:00.000 +09:00 | INFO | main:26]: Praparing to shutdown...
386
- [2023-09-01 00:00:00.000 +09:00 | OK | main:27]: Finished preparation to shutdown.
387
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
388
- [2023-09-01 00:00:00.000 +09:00 | INFO | uvicorn.server:86]: Finished server process [17146]
389
- ```
244
+ - FastAPI HTTP access logging middleware
245
+ - Install with pip: `pip install -U beans-logging[fastapi]` or `pip install -U beans-logging-fastapi`
390
246
 
391
247
  ---
392
248
 
@@ -467,3 +323,4 @@ logger:
467
323
  - <https://github.com/Delgan/loguru>
468
324
  - <https://loguru.readthedocs.io/en/stable/api/logger.html>
469
325
  - <https://loguru.readthedocs.io/en/stable/resources/recipes.html>
326
+ - <https://github.com/bybatkhuu/module.fastapi-logging>
@@ -19,11 +19,6 @@ beans_logging.egg-info/SOURCES.txt
19
19
  beans_logging.egg-info/dependency_links.txt
20
20
  beans_logging.egg-info/requires.txt
21
21
  beans_logging.egg-info/top_level.txt
22
- beans_logging/fastapi/__init__.py
23
- beans_logging/fastapi/_filters.py
24
- beans_logging/fastapi/_formats.py
25
- beans_logging/fastapi/_handlers.py
26
- beans_logging/fastapi/_middlewares.py
27
22
  tests/__init__.py
28
23
  tests/conftest.py
29
24
  tests/test_beans_logging.py
@@ -1,3 +1,6 @@
1
1
  PyYAML<7.0,>=6.0
2
2
  pydantic!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.10.0
3
3
  loguru<1.0.0,>=0.7.2
4
+
5
+ [fastapi]
6
+ beans-logging-fastapi<2.0.0,>=1.0.0
@@ -40,6 +40,7 @@ setup(
40
40
  "pydantic>=1.10.0,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0",
41
41
  "loguru>=0.7.2,<1.0.0",
42
42
  ],
43
+ extras_require={"fastapi": ["beans-logging-fastapi>=1.0.0,<2.0.0"]},
43
44
  classifiers=[
44
45
  "Development Status :: 4 - Beta",
45
46
  "Intended Audience :: Developers",
@@ -1,6 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from ._filters import use_http_filter
4
- from ._formats import http_file_format, http_file_json_format
5
- from ._handlers import add_http_file_handler, add_http_file_json_handler
6
- from ._middlewares import HttpAccessLogMiddleware
@@ -1,22 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from beans_logging.filters import use_all_filter
4
-
5
-
6
- def use_http_filter(record: dict) -> bool:
7
- """Filter message only for http access log handler by checking 'http_info' key in extra.
8
-
9
- Args:
10
- record (dict): Log record as dictionary.
11
-
12
- Returns:
13
- bool: True if record has 'http_info' key in extra, False otherwise.
14
- """
15
-
16
- if not use_all_filter(record):
17
- return False
18
-
19
- if "http_info" not in record["extra"]:
20
- return False
21
-
22
- return True
@@ -1,62 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
-
4
- def http_file_format(record: dict) -> str:
5
- """Http access log file format.
6
-
7
- Args:
8
- record (dict): Log record as dictionary.
9
-
10
- Returns:
11
- str: Format for http access log record.
12
- """
13
-
14
- _MSG_FORMAT = '{client_host} {request_id} {user_id} [{datetime}] "{method} {url_path} HTTP/{http_version}" {status_code} {content_length} "{h_referer}" "{h_user_agent}" {response_time}'
15
-
16
- if "http_info" not in record["extra"]:
17
- return ""
18
-
19
- if "http_message" not in record:
20
- _http_info = record["extra"]["http_info"]
21
- if "datetime" not in _http_info:
22
- _http_info["datetime"] = record["time"].isoformat()
23
-
24
- if "content_length" not in _http_info:
25
- _http_info["content_length"] = 0
26
-
27
- if "h_referer" not in _http_info:
28
- _http_info["h_referer"] = "-"
29
-
30
- if "h_user_agent" not in _http_info:
31
- _http_info["h_user_agent"] = "-"
32
-
33
- if "response_time" not in _http_info:
34
- _http_info["response_time"] = 0
35
-
36
- record["extra"]["http_info"] = _http_info
37
-
38
- _msg = _MSG_FORMAT.format(**_http_info)
39
- record["http_message"] = _msg
40
-
41
- return "{http_message}\n"
42
-
43
-
44
- def http_file_json_format(record: dict) -> str:
45
- """Http access json log file format.
46
-
47
- Args:
48
- record (dict): Log record as dictionary.
49
-
50
- Returns:
51
- str: Format for http access json log record.
52
- """
53
-
54
- if "http_info" not in record["extra"]:
55
- return ""
56
-
57
- _http_info = record["extra"]["http_info"]
58
- if "datetime" not in _http_info:
59
- _http_info["datetime"] = record["time"].isoformat()
60
- record["extra"]["http_info"] = _http_info
61
-
62
- return "{extra[http_info]}\n"
@@ -1,79 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from typing import Union, Callable
4
-
5
- import pydantic
6
-
7
- if "2.0.0" <= pydantic.__version__:
8
- from pydantic import validate_call
9
- else:
10
- from pydantic import validate_arguments as validate_call
11
-
12
- from beans_logging import LoggerLoader
13
-
14
- from ._filters import use_http_filter
15
- from ._formats import http_file_format, http_file_json_format
16
-
17
-
18
- @validate_call(config=dict(arbitrary_types_allowed=True))
19
- def add_http_file_handler(
20
- logger_loader: LoggerLoader,
21
- log_path: str = "http/{app_name}.http.access.log",
22
- err_path: str = "http/{app_name}.http.err.log",
23
- formatter: Union[Callable, str] = http_file_format,
24
- ):
25
- """Add http access log file and error file handler.
26
-
27
- Args:
28
- logger_loader (LoggerLoader, required): LoggerLoader instance.
29
- log_path (str, optional): Log file path. Defaults to "http/{app_name}.http.access.log".
30
- err_path (str, optional): Error log file path. Defaults to "http/{app_name}.http.err.log".
31
- formatter (Union[Callable, str], optional): Log formatter. Defaults to `http_file_format` function.
32
- """
33
-
34
- logger_loader.add_custom_handler(
35
- handler_name="FILE.HTTP",
36
- sink=log_path,
37
- filter=use_http_filter,
38
- format=formatter,
39
- )
40
-
41
- logger_loader.add_custom_handler(
42
- handler_name="FILE.HTTP_ERR",
43
- sink=err_path,
44
- level="WARNING",
45
- filter=use_http_filter,
46
- format=formatter,
47
- )
48
-
49
-
50
- @validate_call(config=dict(arbitrary_types_allowed=True))
51
- def add_http_file_json_handler(
52
- logger_loader: LoggerLoader,
53
- log_path: str = "json.http/{app_name}.json.http.access.log",
54
- err_path: str = "json.http/{app_name}.json.http.err.log",
55
- formatter: Union[Callable, str] = http_file_json_format,
56
- ):
57
- """Add http access json log file and json error file handler.
58
-
59
- Args:
60
- logger_loader (LoggerLoader, required): LoggerLoader instance.
61
- log_path (str, optional): Json log file path. Defaults to "http.json/{app_name}.json.http.access.log".
62
- err_path (str, optional): Json error log file path. Defaults to "http.json/{app_name}.json.http.err.log".
63
- formatter (Union[Callable, str], optional): Log formatter. Defaults to `http_file_json_format` function.
64
- """
65
-
66
- logger_loader.add_custom_handler(
67
- handler_name="FILE.JSON.HTTP",
68
- sink=log_path,
69
- filter=use_http_filter,
70
- format=formatter,
71
- )
72
-
73
- logger_loader.add_custom_handler(
74
- handler_name="FILE.JSON.HTTP_ERR",
75
- sink=err_path,
76
- level="WARNING",
77
- filter=use_http_filter,
78
- format=formatter,
79
- )
@@ -1,262 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- import json
4
- import time
5
- from uuid import uuid4
6
-
7
- from fastapi import Request, Response
8
- from fastapi.concurrency import run_in_threadpool
9
- from starlette.middleware.base import BaseHTTPMiddleware
10
-
11
- from beans_logging import logger
12
-
13
-
14
- class HttpAccessLogMiddleware(BaseHTTPMiddleware):
15
- """Http access log middleware for FastAPI.
16
-
17
- Inherits:
18
- BaseHTTPMiddleware: Base HTTP middleware class from starlette.
19
-
20
- Attributes:
21
- _DEBUG_FORMAT (str ): Default http access log debug message format. Defaults to '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'.
22
- _MSG_FORMAT (str ): Default http access log message format. Defaults to '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" {status_code} {content_length}B {response_time}ms'.
23
-
24
- has_proxy_headers (bool): If True, use proxy headers to get http request info. Defaults to False.
25
- has_cf_headers (bool): If True, use cloudflare headers to get http request info. Defaults to False.
26
- debug_format (str ): Http access log debug message format. Defaults to `HttpAccessLogMiddleware._DEBUG_FORMAT`.
27
- msg_format (str ): Http access log message format. Defaults to `HttpAccessLogMiddleware._MSG_FORMAT`.
28
- use_debug_log (bool): If True, use debug log to log http access log. Defaults to True.
29
- """
30
-
31
- _DEBUG_FORMAT = '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
32
- _MSG_FORMAT = '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" {status_code} {content_length}B {response_time}ms'
33
-
34
- def __init__(
35
- self,
36
- app,
37
- has_proxy_headers: bool = False,
38
- has_cf_headers: bool = False,
39
- debug_format: str = _DEBUG_FORMAT,
40
- msg_format: str = _MSG_FORMAT,
41
- use_debug_log: bool = True,
42
- ):
43
- super().__init__(app)
44
- self.has_proxy_headers = has_proxy_headers
45
- self.has_cf_headers = has_cf_headers
46
- self.debug_format = debug_format
47
- self.msg_format = msg_format
48
- self.use_debug_log = use_debug_log
49
-
50
- async def dispatch(self, request: Request, call_next) -> Response:
51
- _logger = logger.opt(colors=True, record=True)
52
-
53
- _http_info = {}
54
- _http_info["request_id"] = uuid4().hex
55
- if "X-Request-ID" in request.headers:
56
- _http_info["request_id"] = request.headers.get("X-Request-ID")
57
- elif "X-Correlation-ID" in request.headers:
58
- _http_info["request_id"] = request.headers.get("X-Correlation-ID")
59
-
60
- ## Set request_id to request state:
61
- request.state.request_id = _http_info["request_id"]
62
-
63
- _http_info["client_host"] = request.client.host
64
- _http_info["request_proto"] = request.url.scheme
65
- _http_info["request_host"] = (
66
- request.url.hostname if request.url.hostname else ""
67
- )
68
- if (request.url.port != 80) and (request.url.port != 443):
69
- _http_info[
70
- "request_host"
71
- ] = f"{_http_info['request_host']}:{request.url.port}"
72
-
73
- _http_info["request_port"] = request.url.port
74
- _http_info["http_version"] = request.scope["http_version"]
75
-
76
- if self.has_proxy_headers:
77
- if "X-Real-IP" in request.headers:
78
- _http_info["client_host"] = request.headers.get("X-Real-IP")
79
- elif "X-Forwarded-For" in request.headers:
80
- _http_info["client_host"] = request.headers.get(
81
- "X-Forwarded-For"
82
- ).split(",")[0]
83
- _http_info["h_x_forwarded_for"] = request.headers.get("X-Forwarded-For")
84
-
85
- if "X-Forwarded-Proto" in request.headers:
86
- _http_info["request_proto"] = request.headers.get("X-Forwarded-Proto")
87
-
88
- if "X-Forwarded-Host" in request.headers:
89
- _http_info["request_host"] = request.headers.get("X-Forwarded-Host")
90
- elif "Host" in request.headers:
91
- _http_info["request_host"] = request.headers.get("Host")
92
-
93
- if "X-Forwarded-Port" in request.headers:
94
- try:
95
- _http_info["request_port"] = int(
96
- request.headers.get("X-Forwarded-Port")
97
- )
98
- except ValueError:
99
- logger.warning(
100
- f"`X-Forwarded-Port` header value '{request.headers.get('X-Forwarded-Port')}' is invalid, should be parseable to <int>!"
101
- )
102
-
103
- if "Via" in request.headers:
104
- _http_info["h_via"] = request.headers.get("Via")
105
-
106
- if self.has_cf_headers:
107
- if "CF-Connecting-IP" in request.headers:
108
- _http_info["client_host"] = request.headers.get("CF-Connecting-IP")
109
- _http_info["h_cf_connecting_ip"] = request.headers.get(
110
- "CF-Connecting-IP"
111
- )
112
- elif "True-Client-IP" in request.headers:
113
- _http_info["client_host"] = request.headers.get("True-Client-IP")
114
- _http_info["h_true_client_ip"] = request.headers.get(
115
- "True-Client-IP"
116
- )
117
-
118
- if "CF-IPCountry" in request.headers:
119
- _http_info["client_country"] = request.headers.get("CF-IPCountry")
120
- _http_info["h_cf_ipcountry"] = request.headers.get("CF-IPCountry")
121
-
122
- if "CF-RAY" in request.headers:
123
- _http_info["h_cf_ray"] = request.headers.get("CF-RAY")
124
-
125
- if "cf-ipcontinent" in request.headers:
126
- _http_info["h_cf_ipcontinent"] = request.headers.get(
127
- "cf-ipcontinent"
128
- )
129
-
130
- if "cf-ipcity" in request.headers:
131
- _http_info["h_cf_ipcity"] = request.headers.get("cf-ipcity")
132
-
133
- if "cf-iplongitude" in request.headers:
134
- _http_info["h_cf_iplongitude"] = request.headers.get(
135
- "cf-iplongitude"
136
- )
137
-
138
- if "cf-iplatitude" in request.headers:
139
- _http_info["h_cf_iplatitude"] = request.headers.get("cf-iplatitude")
140
-
141
- if "cf-postal-code" in request.headers:
142
- _http_info["h_cf_postal_code"] = request.headers.get(
143
- "cf-postal-code"
144
- )
145
-
146
- if "cf-timezone" in request.headers:
147
- _http_info["h_cf_timezone"] = request.headers.get("cf-timezone")
148
-
149
- _http_info["method"] = request.method
150
- _http_info["url_path"] = request.url.path
151
- if "{" in _http_info["url_path"]:
152
- _http_info["url_path"] = _http_info["url_path"].replace("{", "{{")
153
-
154
- if "}" in _http_info["url_path"]:
155
- _http_info["url_path"] = _http_info["url_path"].replace("}", "}}")
156
-
157
- if request.url.query:
158
- _http_info["url_path"] = f"{request.url.path}?{request.url.query}"
159
-
160
- _http_info["url_query_params"] = request.query_params._dict
161
- _http_info["url_path_params"] = request.path_params
162
-
163
- _http_info["h_referer"] = request.headers.get("Referer", "-")
164
- _http_info["h_user_agent"] = request.headers.get("User-Agent", "-")
165
- _http_info["h_accept"] = request.headers.get("Accept", "")
166
- _http_info["h_content_type"] = request.headers.get("Content-Type", "")
167
-
168
- if "Origin" in request.headers:
169
- _http_info["h_origin"] = request.headers.get("Origin")
170
-
171
- _http_info["user_id"] = "-"
172
- if hasattr(request.state, "user_id"):
173
- _http_info["user_id"] = str(request.state.user_id)
174
-
175
- ## Debug log:
176
- if self.use_debug_log:
177
- _debug_msg = self.debug_format.format(**_http_info)
178
-
179
- # _logger.debug(_debug_msg)
180
- await run_in_threadpool(
181
- _logger.debug,
182
- _debug_msg,
183
- )
184
- ## Debug log
185
-
186
- ## Set http info to request state:
187
- request.state.http_info = _http_info
188
-
189
- _start_time = time.time()
190
- ## Process request:
191
- response = await call_next(request)
192
- ## Response processed.
193
- _http_info["response_time"] = round((time.time() - _start_time) * 1000, 1)
194
-
195
- if "X-Process-Time" in response.headers:
196
- try:
197
- _http_info["response_time"] = float(
198
- response.headers.get("X-Process-Time")
199
- )
200
- except ValueError:
201
- logger.warning(
202
- f"`X-Process-Time` header value '{response.headers.get('X-Process-Time')}' is invalid, should be parseable to <float>!"
203
- )
204
- else:
205
- response.headers["X-Process-Time"] = str(_http_info["response_time"])
206
-
207
- if "X-Request-ID" not in response.headers:
208
- response.headers["X-Request-ID"] = _http_info["request_id"]
209
-
210
- if hasattr(request.state, "user_id"):
211
- _http_info["user_id"] = str(request.state.user_id)
212
-
213
- _http_info["status_code"] = response.status_code
214
- _http_info["content_length"] = 0
215
- if "Content-Length" in response.headers:
216
- try:
217
- _http_info["content_length"] = int(
218
- response.headers.get("Content-Length")
219
- )
220
- except ValueError:
221
- logger.warning(
222
- f"`Content-Length` header value '{response.headers.get('Content-Length')}' is invalid, should be parseable to <int>!"
223
- )
224
-
225
- try:
226
- json.dumps(_http_info)
227
- except TypeError:
228
- logger.warning(
229
- "Can not serialize `http_info` to json string in HttpAccessLogMiddleware!"
230
- )
231
-
232
- ## Http access log:
233
- _LEVEL = "INFO"
234
- _msg_format = self.msg_format
235
- if _http_info["status_code"] < 200:
236
- _LEVEL = "DEBUG"
237
- _msg_format = f'<d>{_msg_format.replace("{status_code}", "<n><b><k>{status_code}</k></b></n>")}</d>'
238
- elif (200 <= _http_info["status_code"]) and (_http_info["status_code"] < 300):
239
- _LEVEL = "SUCCESS"
240
- _msg_format = f'<w>{_msg_format.replace("{status_code}", "<lvl>{status_code}</lvl>")}</w>'
241
- elif (300 <= _http_info["status_code"]) and (_http_info["status_code"] < 400):
242
- _LEVEL = "INFO"
243
- _msg_format = f'<d>{_msg_format.replace("{status_code}", "<n><b><c>{status_code}</c></b></n>")}</d>'
244
- elif (400 <= _http_info["status_code"]) and (_http_info["status_code"] < 500):
245
- _LEVEL = "WARNING"
246
- _msg_format = _msg_format.replace("{status_code}", "<r>{status_code}</r>")
247
- elif 500 <= _http_info["status_code"]:
248
- _LEVEL = "ERROR"
249
- _msg_format = (
250
- f'{_msg_format.replace("{status_code}", "<n>{status_code}</n>")}'
251
- )
252
-
253
- _msg = _msg_format.format(**_http_info)
254
- # _logger.bind(http_info=_http_info).log(_LEVEL, _msg)
255
- await run_in_threadpool(
256
- _logger.bind(http_info=_http_info).log,
257
- _LEVEL,
258
- _msg,
259
- )
260
- ## Http access log
261
-
262
- return response
File without changes
File without changes