beans-logging-fastapi 3.0.0__tar.gz → 4.0.1__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_fastapi-3.0.0/src/beans_logging_fastapi.egg-info → beans_logging_fastapi-4.0.1}/PKG-INFO +41 -36
  2. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/README.md +37 -32
  3. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/pyproject.toml +1 -5
  4. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/requirements/requirements.dev.txt +1 -1
  5. beans_logging_fastapi-4.0.1/requirements.txt +2 -0
  6. beans_logging_fastapi-4.0.1/src/beans_logging_fastapi/__version__.py +1 -0
  7. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi/_async.py +7 -7
  8. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi/_core.py +11 -8
  9. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi/config.py +14 -5
  10. beans_logging_fastapi-4.0.1/src/beans_logging_fastapi/constants.py +23 -0
  11. beans_logging_fastapi-4.0.1/src/beans_logging_fastapi/filters.py +74 -0
  12. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi/formats.py +4 -2
  13. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi/middlewares.py +36 -24
  14. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1/src/beans_logging_fastapi.egg-info}/PKG-INFO +41 -36
  15. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi.egg-info/requires.txt +2 -2
  16. beans_logging_fastapi-3.0.0/requirements.txt +0 -2
  17. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/__version__.py +0 -1
  18. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/constants.py +0 -12
  19. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/filters.py +0 -30
  20. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/.python-version +0 -0
  21. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/LICENSE.txt +0 -0
  22. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/requirements/requirements.build.txt +0 -0
  23. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/requirements/requirements.docs.txt +0 -0
  24. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/requirements/requirements.test.txt +0 -0
  25. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/setup.cfg +0 -0
  26. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/setup.py +0 -0
  27. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi/__init__.py +0 -0
  28. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi.egg-info/SOURCES.txt +0 -0
  29. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi.egg-info/dependency_links.txt +0 -0
  30. {beans_logging_fastapi-3.0.0 → beans_logging_fastapi-4.0.1}/src/beans_logging_fastapi.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beans_logging_fastapi
3
- Version: 3.0.0
4
- Summary: This is a middleware for FastAPI HTTP access logs. It is based on 'beans-logging' package.
3
+ Version: 4.0.1
4
+ Summary: This is a HTTP access log module for FastAPI based on 'beans-logging' package.
5
5
  Author-email: Batkhuu Byambajav <batkhuu10@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bybatkhuu/module-fastapi-logging
7
7
  Project-URL: Documentation, https://fastapi-logging-docs.bybatkhuu.dev
@@ -22,7 +22,7 @@ Requires-Python: <4.0,>=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE.txt
24
24
  Requires-Dist: fastapi<1.0.0,>=0.99.1
25
- Requires-Dist: beans-logging<9.0.0,>=8.0.2
25
+ Requires-Dist: beans-logging<10.0.0,>=9.0.2
26
26
  Provides-Extra: test
27
27
  Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "test"
28
28
  Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "test"
@@ -55,7 +55,7 @@ Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "dev"
55
55
  Requires-Dist: mike<3.0.0,>=2.1.3; extra == "dev"
56
56
  Requires-Dist: pyright<2.0.0,>=1.1.392; extra == "dev"
57
57
  Requires-Dist: pre-commit<5.0.0,>=4.0.1; extra == "dev"
58
- Requires-Dist: uvicorn[standard]<1.0.0,>=0.23.0; extra == "dev"
58
+ Requires-Dist: fastapi[standard]<1.0.0,>=0.99.1; extra == "dev"
59
59
  Dynamic: license-file
60
60
 
61
61
  # FastAPI Logging (beans-logging-fastapi)
@@ -64,7 +64,7 @@ Dynamic: license-file
64
64
  [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bybatkhuu/module-fastapi-logging/2.build-publish.yml?logo=GitHub)](https://github.com/bybatkhuu/module-fastapi-logging/actions/workflows/2.build-publish.yml)
65
65
  [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/bybatkhuu/module-fastapi-logging?logo=GitHub&color=blue)](https://github.com/bybatkhuu/module-fastapi-logging/releases)
66
66
 
67
- This is a HTTP access logging module for **FastAPI** based on **'beans-logging'** package.
67
+ This is a HTTP access log module for **FastAPI** based on **'beans-logging'** package.
68
68
 
69
69
  ## ✨ Features
70
70
 
@@ -408,24 +408,24 @@ uvicorn main:app --host=0.0.0.0 --port=8000
408
408
  **Output**:
409
409
 
410
410
  ```txt
411
- [2026-01-01 12:00:00.907 +09:00 | TRACE | beans_logging.intercepters:96]: Intercepted modules: ['concurrent.futures', 'potato_util', 'watchfiles.watcher', 'potato_util.io._sync', 'concurrent', 'uvicorn', 'fastapi', 'uvicorn.error', 'dotenv.main', 'watchfiles.main', 'asyncio', 'dotenv', 'potato_util._base', 'potato_util.io', 'watchfiles']; Muted modules: ['uvicorn.access'];
412
- [2026-01-01 12:00:00.908 +09:00 | INFO | uvicorn.server:84]: Started server process [64590]
413
- [2026-01-01 12:00:00.909 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
414
- [2026-01-01 12:00:00.909 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
415
- [2026-01-01 12:00:00.909 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
416
- [2026-01-01 12:00:00.909 +09:00 | INFO | lifespan:21]: Preparing to startup...
417
- [2026-01-01 12:00:00.909 +09:00 | OK | lifespan:24]: Finished preparation to startup.
418
- [2026-01-01 12:00:00.909 +09:00 | INFO | lifespan:25]: Version: 0.0.0
419
- [2026-01-01 12:00:00.909 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
420
- [2026-01-01 12:00:00.911 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
421
- [2026-01-01 12:00:01.582 +09:00 | DEBUG | anyio._backends._asyncio:986]: [c433596f728744aaa1cde63399dd3995] 127.0.0.1 - "GET / HTTP/1.1"
422
- [2026-01-01 12:00:01.586 +09:00 | OK | anyio._backends._asyncio:986]: [c433596f728744aaa1cde63399dd3995] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 3.1ms
423
- ^C[2026-01-01 12:00:02.074 +09:00 | INFO | uvicorn.server:264]: Shutting down
424
- [2026-01-01 12:00:02.177 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
425
- [2026-01-01 12:00:02.178 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
426
- [2026-01-01 12:00:02.179 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
427
- [2026-01-01 12:00:02.179 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
428
- [2026-01-01 12:00:02.180 +09:00 | INFO | uvicorn.server:94]: Finished server process [64590]
411
+ [2026-01-01 12:00:00.002 +09:00 | TRACE | beans_logging.intercepters:96]: Intercepted modules: ['uvicorn', 'potato_util', 'fastapi', 'uvicorn.error', 'watchfiles.watcher', 'concurrent.futures', 'watchfiles', 'asyncio', 'concurrent', 'potato_util._base', 'dotenv', 'dotenv.main', 'watchfiles.main', 'potato_util.io', 'potato_util.io._sync']; Muted modules: ['uvicorn.access'];
412
+ [2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.server:84]: Started server process [88375]
413
+ [2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
414
+ [2026-01-01 12:00:00.004 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
415
+ [2026-01-01 12:00:00.004 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
416
+ [2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:21]: Preparing to startup...
417
+ [2026-01-01 12:00:00.004 +09:00 | OK | lifespan:24]: Finished preparation to startup.
418
+ [2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:25]: Version: 0.0.0
419
+ [2026-01-01 12:00:00.005 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
420
+ [2026-01-01 12:00:00.006 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
421
+ [2026-01-01 12:00:01.775 +09:00 | DEBUG ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1"
422
+ [2026-01-01 12:00:01.783 +09:00 | OK ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 5.7ms
423
+ ^C[2026-01-01 12:00:02.368 +09:00 | INFO | uvicorn.server:264]: Shutting down
424
+ [2026-01-01 12:00:02.470 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
425
+ [2026-01-01 12:00:02.472 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
426
+ [2026-01-01 12:00:02.472 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
427
+ [2026-01-01 12:00:02.473 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
428
+ [2026-01-01 12:00:02.474 +09:00 | INFO | uvicorn.server:94]: Finished server process [88375]
429
429
  ```
430
430
 
431
431
  👍
@@ -450,12 +450,12 @@ logger:
450
450
  rotate_time: "00:00:00"
451
451
  retention: 90
452
452
  encoding: utf8
453
- custom_serialize: false
453
+ use_custom_serialize: false
454
454
  http:
455
455
  std:
456
- format_str: '<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'
457
- err_format_str: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
458
- debug_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
456
+ msg_format_str: '<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'
457
+ err_msg_format_str: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
458
+ debug_msg_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
459
459
  file:
460
460
  format_str: '{client_host} {request_id} {user_id} [{datetime}] "{method} {url_path} HTTP/{http_version}" {status_code} {content_length} "{h_referer}" "{h_user_agent}" {response_time}'
461
461
  tz: localtime
@@ -469,45 +469,50 @@ logger:
469
469
  include_modules: []
470
470
  mute_modules: [uvicorn.access]
471
471
  handlers:
472
- default.all.std_handler:
472
+ all_std_handler:
473
473
  enabled: true
474
474
  h_type: STD
475
475
  format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> | <w>{name}:{line}</w>]: <level>{message}</level>"
476
476
  colorize: true
477
- default.all.file_handler:
477
+ all_file_handler:
478
478
  enabled: true
479
479
  h_type: FILE
480
480
  sink: "{app_name}.all.log"
481
- default.err.file_handler:
481
+ err_file_handler:
482
482
  enabled: true
483
483
  h_type: FILE
484
484
  sink: "{app_name}.err.log"
485
485
  error: true
486
- default.all.json_handler:
486
+ all_json_handler:
487
487
  enabled: true
488
488
  h_type: FILE
489
489
  sink: "json/{app_name}.all.json.log"
490
490
  serialize: true
491
- default.err.json_handler:
491
+ err_json_handler:
492
492
  enabled: true
493
493
  h_type: FILE
494
494
  sink: "json/{app_name}.err.json.log"
495
495
  serialize: true
496
496
  error: true
497
- http.access.file_handler:
497
+ http_access_std_handler:
498
+ enabled: true
499
+ h_type: STD
500
+ format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> ]: <level>{message}</level>"
501
+ colorize: true
502
+ http_access_file_handler:
498
503
  enabled: true
499
504
  h_type: FILE
500
505
  sink: "http/{app_name}.http-access.log"
501
- http.err.file_handler:
506
+ http_err_file_handler:
502
507
  enabled: true
503
508
  h_type: FILE
504
509
  sink: "http/{app_name}.http-err.log"
505
510
  error: true
506
- http.access.json_handler:
511
+ http_access_json_handler:
507
512
  enabled: true
508
513
  h_type: FILE
509
514
  sink: "http.json/{app_name}.http-access.json.log"
510
- http.err.json_handler:
515
+ http_err_json_handler:
511
516
  enabled: true
512
517
  h_type: FILE
513
518
  sink: "http.json/{app_name}.http-err.json.log"
@@ -4,7 +4,7 @@
4
4
  [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bybatkhuu/module-fastapi-logging/2.build-publish.yml?logo=GitHub)](https://github.com/bybatkhuu/module-fastapi-logging/actions/workflows/2.build-publish.yml)
5
5
  [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/bybatkhuu/module-fastapi-logging?logo=GitHub&color=blue)](https://github.com/bybatkhuu/module-fastapi-logging/releases)
6
6
 
7
- This is a HTTP access logging module for **FastAPI** based on **'beans-logging'** package.
7
+ This is a HTTP access log module for **FastAPI** based on **'beans-logging'** package.
8
8
 
9
9
  ## ✨ Features
10
10
 
@@ -348,24 +348,24 @@ uvicorn main:app --host=0.0.0.0 --port=8000
348
348
  **Output**:
349
349
 
350
350
  ```txt
351
- [2026-01-01 12:00:00.907 +09:00 | TRACE | beans_logging.intercepters:96]: Intercepted modules: ['concurrent.futures', 'potato_util', 'watchfiles.watcher', 'potato_util.io._sync', 'concurrent', 'uvicorn', 'fastapi', 'uvicorn.error', 'dotenv.main', 'watchfiles.main', 'asyncio', 'dotenv', 'potato_util._base', 'potato_util.io', 'watchfiles']; Muted modules: ['uvicorn.access'];
352
- [2026-01-01 12:00:00.908 +09:00 | INFO | uvicorn.server:84]: Started server process [64590]
353
- [2026-01-01 12:00:00.909 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
354
- [2026-01-01 12:00:00.909 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
355
- [2026-01-01 12:00:00.909 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
356
- [2026-01-01 12:00:00.909 +09:00 | INFO | lifespan:21]: Preparing to startup...
357
- [2026-01-01 12:00:00.909 +09:00 | OK | lifespan:24]: Finished preparation to startup.
358
- [2026-01-01 12:00:00.909 +09:00 | INFO | lifespan:25]: Version: 0.0.0
359
- [2026-01-01 12:00:00.909 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
360
- [2026-01-01 12:00:00.911 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
361
- [2026-01-01 12:00:01.582 +09:00 | DEBUG | anyio._backends._asyncio:986]: [c433596f728744aaa1cde63399dd3995] 127.0.0.1 - "GET / HTTP/1.1"
362
- [2026-01-01 12:00:01.586 +09:00 | OK | anyio._backends._asyncio:986]: [c433596f728744aaa1cde63399dd3995] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 3.1ms
363
- ^C[2026-01-01 12:00:02.074 +09:00 | INFO | uvicorn.server:264]: Shutting down
364
- [2026-01-01 12:00:02.177 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
365
- [2026-01-01 12:00:02.178 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
366
- [2026-01-01 12:00:02.179 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
367
- [2026-01-01 12:00:02.179 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
368
- [2026-01-01 12:00:02.180 +09:00 | INFO | uvicorn.server:94]: Finished server process [64590]
351
+ [2026-01-01 12:00:00.002 +09:00 | TRACE | beans_logging.intercepters:96]: Intercepted modules: ['uvicorn', 'potato_util', 'fastapi', 'uvicorn.error', 'watchfiles.watcher', 'concurrent.futures', 'watchfiles', 'asyncio', 'concurrent', 'potato_util._base', 'dotenv', 'dotenv.main', 'watchfiles.main', 'potato_util.io', 'potato_util.io._sync']; Muted modules: ['uvicorn.access'];
352
+ [2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.server:84]: Started server process [88375]
353
+ [2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
354
+ [2026-01-01 12:00:00.004 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
355
+ [2026-01-01 12:00:00.004 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
356
+ [2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:21]: Preparing to startup...
357
+ [2026-01-01 12:00:00.004 +09:00 | OK | lifespan:24]: Finished preparation to startup.
358
+ [2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:25]: Version: 0.0.0
359
+ [2026-01-01 12:00:00.005 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
360
+ [2026-01-01 12:00:00.006 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
361
+ [2026-01-01 12:00:01.775 +09:00 | DEBUG ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1"
362
+ [2026-01-01 12:00:01.783 +09:00 | OK ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 5.7ms
363
+ ^C[2026-01-01 12:00:02.368 +09:00 | INFO | uvicorn.server:264]: Shutting down
364
+ [2026-01-01 12:00:02.470 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
365
+ [2026-01-01 12:00:02.472 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
366
+ [2026-01-01 12:00:02.472 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
367
+ [2026-01-01 12:00:02.473 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
368
+ [2026-01-01 12:00:02.474 +09:00 | INFO | uvicorn.server:94]: Finished server process [88375]
369
369
  ```
370
370
 
371
371
  👍
@@ -390,12 +390,12 @@ logger:
390
390
  rotate_time: "00:00:00"
391
391
  retention: 90
392
392
  encoding: utf8
393
- custom_serialize: false
393
+ use_custom_serialize: false
394
394
  http:
395
395
  std:
396
- format_str: '<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'
397
- err_format_str: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
398
- debug_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
396
+ msg_format_str: '<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'
397
+ err_msg_format_str: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
398
+ debug_msg_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
399
399
  file:
400
400
  format_str: '{client_host} {request_id} {user_id} [{datetime}] "{method} {url_path} HTTP/{http_version}" {status_code} {content_length} "{h_referer}" "{h_user_agent}" {response_time}'
401
401
  tz: localtime
@@ -409,45 +409,50 @@ logger:
409
409
  include_modules: []
410
410
  mute_modules: [uvicorn.access]
411
411
  handlers:
412
- default.all.std_handler:
412
+ all_std_handler:
413
413
  enabled: true
414
414
  h_type: STD
415
415
  format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> | <w>{name}:{line}</w>]: <level>{message}</level>"
416
416
  colorize: true
417
- default.all.file_handler:
417
+ all_file_handler:
418
418
  enabled: true
419
419
  h_type: FILE
420
420
  sink: "{app_name}.all.log"
421
- default.err.file_handler:
421
+ err_file_handler:
422
422
  enabled: true
423
423
  h_type: FILE
424
424
  sink: "{app_name}.err.log"
425
425
  error: true
426
- default.all.json_handler:
426
+ all_json_handler:
427
427
  enabled: true
428
428
  h_type: FILE
429
429
  sink: "json/{app_name}.all.json.log"
430
430
  serialize: true
431
- default.err.json_handler:
431
+ err_json_handler:
432
432
  enabled: true
433
433
  h_type: FILE
434
434
  sink: "json/{app_name}.err.json.log"
435
435
  serialize: true
436
436
  error: true
437
- http.access.file_handler:
437
+ http_access_std_handler:
438
+ enabled: true
439
+ h_type: STD
440
+ format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> ]: <level>{message}</level>"
441
+ colorize: true
442
+ http_access_file_handler:
438
443
  enabled: true
439
444
  h_type: FILE
440
445
  sink: "http/{app_name}.http-access.log"
441
- http.err.file_handler:
446
+ http_err_file_handler:
442
447
  enabled: true
443
448
  h_type: FILE
444
449
  sink: "http/{app_name}.http-err.log"
445
450
  error: true
446
- http.access.json_handler:
451
+ http_access_json_handler:
447
452
  enabled: true
448
453
  h_type: FILE
449
454
  sink: "http.json/{app_name}.http-access.json.log"
450
- http.err.json_handler:
455
+ http_err_json_handler:
451
456
  enabled: true
452
457
  h_type: FILE
453
458
  sink: "http.json/{app_name}.http-err.json.log"
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "beans_logging_fastapi"
7
7
  authors = [{ name = "Batkhuu Byambajav", email = "batkhuu10@gmail.com" }]
8
- description = "This is a middleware for FastAPI HTTP access logs. It is based on 'beans-logging' package."
8
+ description = "This is a HTTP access log module for FastAPI based on 'beans-logging' package."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10,<4.0"
11
11
  keywords = [
@@ -51,10 +51,6 @@ dev = { file = [
51
51
  "./requirements/requirements.dev.txt",
52
52
  ] }
53
53
 
54
- # [tool.pyright]
55
- # venvPath = "."
56
- # venv = ".venv"
57
-
58
54
  [project.urls]
59
55
  Homepage = "https://github.com/bybatkhuu/module-fastapi-logging"
60
56
  Documentation = "https://fastapi-logging-docs.bybatkhuu.dev"
@@ -1,3 +1,3 @@
1
1
  pyright>=1.1.392,<2.0.0
2
2
  pre-commit>=4.0.1,<5.0.0
3
- uvicorn[standard]>=0.23.0,<1.0.0
3
+ fastapi[standard]>=0.99.1,<1.0.0
@@ -0,0 +1,2 @@
1
+ fastapi>=0.99.1,<1.0.0
2
+ beans-logging>=9.0.2,<10.0.0
@@ -0,0 +1 @@
1
+ __version__ = "4.0.1"
@@ -11,17 +11,17 @@ from beans_logging import logger, Logger
11
11
  async def async_log_http_error(
12
12
  request: Request,
13
13
  status_code: int,
14
- format_str: str = (
15
- '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> '
16
- 'HTTP/{http_version}" <n>{status_code}</n>'
14
+ msg_format_str: str = (
15
+ '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u>'
16
+ ' HTTP/{http_version}" <n>{status_code}</n>'
17
17
  ),
18
18
  ) -> None:
19
19
  """Log HTTP error for unhandled Exception.
20
20
 
21
21
  Args:
22
- request (Request, required): Request instance.
23
- status_code (int , required): HTTP status code.
24
- format_str (str , optional): Message format. Defaults to
22
+ request (Request, required): Request instance.
23
+ status_code (int , required): HTTP status code.
24
+ msg_format_str (str , optional): Message format. Defaults to
25
25
  '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"
26
26
  <n>{status_code}</n>'.
27
27
  """
@@ -33,7 +33,7 @@ async def async_log_http_error(
33
33
  _http_info: dict[str, Any] = request.state.http_info
34
34
  _http_info["status_code"] = status_code
35
35
 
36
- _msg = format_str.format(**_http_info)
36
+ _msg = msg_format_str.format(**_http_info)
37
37
  _logger: Logger = logger.opt(colors=True, record=True).bind(http_info=_http_info)
38
38
  await run_in_threadpool(_logger.error, _msg)
39
39
  return
@@ -11,14 +11,15 @@ else:
11
11
  from beans_logging import LoggerLoader
12
12
 
13
13
  from .constants import (
14
+ HTTP_ACCESS_STD_HANDLER_NAME,
14
15
  HTTP_ACCESS_FILE_HANDLER_NAME,
15
16
  HTTP_ERR_FILE_HANDLER_NAME,
16
17
  HTTP_ACCESS_JSON_HANDLER_NAME,
17
18
  HTTP_ERR_JSON_HANDLER_NAME,
18
19
  )
19
20
  from .config import LoggerConfigPM
20
- from .filters import use_http_filter
21
- from .formats import http_file_format, http_file_json_format
21
+ from .filters import http_std_filter, http_all_file_filter
22
+ from .formats import http_file_format, http_json_format
22
23
  from .middlewares import (
23
24
  HttpAccessLogMiddleware,
24
25
  RequestHTTPInfoMiddleware,
@@ -56,8 +57,8 @@ def add_logger(
56
57
  app.add_middleware(ResponseHTTPInfoMiddleware)
57
58
  app.add_middleware(
58
59
  HttpAccessLogMiddleware,
59
- debug_format_str=config.http.std.debug_format_str,
60
- format_str=config.http.std.format_str,
60
+ debug_msg_format_str=config.http.std.debug_msg_format_str,
61
+ msg_format_str=config.http.std.msg_format_str,
61
62
  )
62
63
  app.add_middleware(
63
64
  RequestHTTPInfoMiddleware,
@@ -66,10 +67,12 @@ def add_logger(
66
67
  )
67
68
 
68
69
  for _name, _handler in logger_loader.config.handlers.items():
69
- if (_name == HTTP_ACCESS_FILE_HANDLER_NAME) or (
70
+ if _name == HTTP_ACCESS_STD_HANDLER_NAME:
71
+ _handler.filter_ = http_std_filter
72
+ elif (_name == HTTP_ACCESS_FILE_HANDLER_NAME) or (
70
73
  _name == HTTP_ERR_FILE_HANDLER_NAME
71
74
  ):
72
- _handler.filter_ = use_http_filter
75
+ _handler.filter_ = http_all_file_filter
73
76
  _handler.format_ = lambda record: http_file_format(
74
77
  record=record,
75
78
  format_str=config.http.file.format_str,
@@ -78,8 +81,8 @@ def add_logger(
78
81
  elif (_name == HTTP_ACCESS_JSON_HANDLER_NAME) or (
79
82
  _name == HTTP_ERR_JSON_HANDLER_NAME
80
83
  ):
81
- _handler.filter_ = use_http_filter
82
- _handler.format_ = http_file_json_format
84
+ _handler.filter_ = http_all_file_filter
85
+ _handler.format_ = http_json_format
83
86
 
84
87
  logger: Logger = logger_loader.load()
85
88
  return logger
@@ -3,7 +3,7 @@ from typing import Any
3
3
  import potato_util as utils
4
4
  from pydantic import Field, field_validator
5
5
 
6
- from beans_logging.constants import LogHandlerTypeEnum
6
+ from beans_logging.constants import LogHandlerTypeEnum, DEFAULT_HANDLER_NAMES
7
7
  from beans_logging.schemas import LogHandlerPM
8
8
  from beans_logging.config import (
9
9
  get_default_handlers as get_base_handlers,
@@ -13,6 +13,7 @@ from beans_logging.config import (
13
13
  )
14
14
 
15
15
  from .constants import (
16
+ HTTP_ACCESS_STD_HANDLER_NAME,
16
17
  HTTP_ACCESS_FILE_HANDLER_NAME,
17
18
  HTTP_ERR_FILE_HANDLER_NAME,
18
19
  HTTP_ACCESS_JSON_HANDLER_NAME,
@@ -29,10 +30,18 @@ def get_default_handlers() -> dict[str, LogHandlerPM]:
29
30
 
30
31
  _base_handlers = get_base_handlers()
31
32
  for _name, _handler in _base_handlers.items():
32
- if _name.startswith("default"):
33
+ if _name in DEFAULT_HANDLER_NAMES:
33
34
  _handler.enabled = True
34
35
 
35
36
  _http_handlers: dict[str, LogHandlerPM] = {
37
+ HTTP_ACCESS_STD_HANDLER_NAME: LogHandlerPM(
38
+ h_type=LogHandlerTypeEnum.STD,
39
+ format_=(
40
+ "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> ]:"
41
+ " <level>{message}</level>"
42
+ ),
43
+ colorize=True,
44
+ ),
36
45
  HTTP_ACCESS_FILE_HANDLER_NAME: LogHandlerPM(
37
46
  h_type=LogHandlerTypeEnum.FILE,
38
47
  sink="http/{app_name}.http-access.log",
@@ -63,7 +72,7 @@ def get_default_intercept() -> InterceptConfigPM:
63
72
 
64
73
 
65
74
  class StdConfigPM(ExtraBaseModel):
66
- format_str: str = Field(
75
+ msg_format_str: str = Field(
67
76
  default=(
68
77
  '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
69
78
  " {status_code} {content_length}B {response_time}ms"
@@ -71,7 +80,7 @@ class StdConfigPM(ExtraBaseModel):
71
80
  min_length=8,
72
81
  max_length=512,
73
82
  )
74
- err_format_str: str = Field(
83
+ err_msg_format_str: str = Field(
75
84
  default=(
76
85
  '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
77
86
  " <n>{status_code}</n>"
@@ -79,7 +88,7 @@ class StdConfigPM(ExtraBaseModel):
79
88
  min_length=8,
80
89
  max_length=512,
81
90
  )
82
- debug_format_str: str = Field(
91
+ debug_msg_format_str: str = Field(
83
92
  default='<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"',
84
93
  min_length=8,
85
94
  max_length=512,
@@ -0,0 +1,23 @@
1
+ HTTP_ACCESS_STD_HANDLER_NAME = "http_access_std_handler"
2
+ HTTP_ACCESS_FILE_HANDLER_NAME = "http_access_file_handler"
3
+ HTTP_ERR_FILE_HANDLER_NAME = "http_err_file_handler"
4
+ HTTP_ACCESS_JSON_HANDLER_NAME = "http_access_json_handler"
5
+ HTTP_ERR_JSON_HANDLER_NAME = "http_err_json_handler"
6
+
7
+ HTTP_HANDLER_NAMES = [
8
+ HTTP_ACCESS_STD_HANDLER_NAME,
9
+ HTTP_ACCESS_FILE_HANDLER_NAME,
10
+ HTTP_ERR_FILE_HANDLER_NAME,
11
+ HTTP_ACCESS_JSON_HANDLER_NAME,
12
+ HTTP_ERR_JSON_HANDLER_NAME,
13
+ ]
14
+
15
+
16
+ __all__ = [
17
+ "HTTP_ACCESS_STD_HANDLER_NAME",
18
+ "HTTP_ACCESS_FILE_HANDLER_NAME",
19
+ "HTTP_ERR_FILE_HANDLER_NAME",
20
+ "HTTP_ACCESS_JSON_HANDLER_NAME",
21
+ "HTTP_ERR_JSON_HANDLER_NAME",
22
+ "HTTP_HANDLER_NAMES",
23
+ ]
@@ -0,0 +1,74 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from loguru import Record
5
+ else:
6
+ from beans_logging.typing import Record
7
+
8
+ from beans_logging.filters import all_handlers_filter
9
+
10
+ from .constants import HTTP_ACCESS_STD_HANDLER_NAME
11
+
12
+
13
+ def http_filter(record: "Record") -> bool:
14
+ """Filter message only for http access log handler by checking 'http_info' key in extra.
15
+
16
+ Args:
17
+ record (Record, required): Log record as dictionary.
18
+
19
+ Returns:
20
+ bool: True if record has 'http_info' key in extra, False otherwise.
21
+ """
22
+
23
+ if not all_handlers_filter(record):
24
+ return False
25
+
26
+ if "http_info" not in record["extra"]:
27
+ return False
28
+
29
+ return True
30
+
31
+
32
+ def http_std_filter(record: "Record") -> bool:
33
+ """Filter message only for http std log handler.
34
+
35
+ Args:
36
+ record (Record, required): Log record as dictionary.
37
+
38
+ Returns:
39
+ bool: True if record does not have 'disable_{HTTP_ACCESS_STD_HANDLER_NAME}' key in extra, False otherwise.
40
+ """
41
+
42
+ if not http_filter(record):
43
+ return False
44
+
45
+ if record["extra"].get(f"disable_{HTTP_ACCESS_STD_HANDLER_NAME}", False):
46
+ return False
47
+
48
+ return True
49
+
50
+
51
+ def http_all_file_filter(record: "Record") -> bool:
52
+ """Filter message only for http file log handler.
53
+
54
+ Args:
55
+ record (Record, required): Log record as dictionary.
56
+
57
+ Returns:
58
+ bool: True if record does not have 'disable_http_all_file_handlers' key in extra, False otherwise.
59
+ """
60
+
61
+ if not http_filter(record):
62
+ return False
63
+
64
+ if record["extra"].get("disable_http_all_file_handlers", False):
65
+ return False
66
+
67
+ return True
68
+
69
+
70
+ __all__ = [
71
+ "http_filter",
72
+ "http_std_filter",
73
+ "http_all_file_filter",
74
+ ]
@@ -5,6 +5,8 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  if TYPE_CHECKING:
7
7
  from loguru import Record
8
+ else:
9
+ from beans_logging.typing import Record
8
10
 
9
11
 
10
12
  def http_file_format(
@@ -62,7 +64,7 @@ def http_file_format(
62
64
  return "{extra[http_message]}\n"
63
65
 
64
66
 
65
- def http_file_json_format(record: "Record") -> str:
67
+ def http_json_format(record: "Record") -> str:
66
68
  """Http access json log file format.
67
69
 
68
70
  Args:
@@ -91,5 +93,5 @@ def http_file_json_format(record: "Record") -> str:
91
93
 
92
94
  __all__ = [
93
95
  "http_file_format",
94
- "http_file_json_format",
96
+ "http_json_format",
95
97
  ]
@@ -235,20 +235,24 @@ class HttpAccessLogMiddleware(BaseHTTPMiddleware):
235
235
  BaseHTTPMiddleware: Base HTTP middleware class from starlette.
236
236
 
237
237
  Attributes:
238
- _DEBUG_FORMAT_STR (str ): Default http access log debug message format. Defaults to
238
+ _DEBUG_MSG_FORMAT_STR (str ): Default http access log debug message format. Defaults to
239
239
  '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'.
240
- _FORMAT_STR (str ): Default http access log message format. Defaults to
240
+ _MSG_FORMAT_STR (str ): Default http access log message format. Defaults to
241
241
  '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"
242
242
  {status_code} {content_length}B {response_time}ms'.
243
243
 
244
- debug_format_str (str ): Http access log debug message format. Defaults to
245
- `HttpAccessLogMiddleware._DEBUG_FORMAT_STR`.
246
- format_str (str ): Http access log message format. Defaults to `HttpAccessLogMiddleware._FORMAT_STR`.
247
- use_debug_log (bool): If True, use debug log to log http access log. Defaults to True.
244
+ debug_msg_format_str (str ): Http access log debug message format.
245
+ Defaults to `HttpAccessLogMiddleware._DEBUG_MSG_FORMAT_STR`.
246
+ msg_format_str (str ): Http access log message format.
247
+ Defaults to `HttpAccessLogMiddleware._MSG_FORMAT_STR`.
248
+ use_debug_log (bool): If True, use debug log to log http access log. Defaults to True.
248
249
  """
249
250
 
250
- _DEBUG_FORMAT_STR = '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
251
- _FORMAT_STR = (
251
+ _DEBUG_MSG_FORMAT_STR = (
252
+ '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u>'
253
+ ' HTTP/{http_version}"'
254
+ )
255
+ _MSG_FORMAT_STR = (
252
256
  '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
253
257
  " {status_code} {content_length}B {response_time}ms"
254
258
  )
@@ -256,17 +260,19 @@ class HttpAccessLogMiddleware(BaseHTTPMiddleware):
256
260
  def __init__(
257
261
  self,
258
262
  app,
259
- debug_format_str: str = _DEBUG_FORMAT_STR,
260
- format_str: str = _FORMAT_STR,
263
+ debug_msg_format_str: str = _DEBUG_MSG_FORMAT_STR,
264
+ msg_format_str: str = _MSG_FORMAT_STR,
261
265
  use_debug_log: bool = True,
262
266
  ):
263
267
  super().__init__(app)
264
- self.debug_format_str = debug_format_str
265
- self.format_str = format_str
268
+ self.debug_msg_format_str = debug_msg_format_str
269
+ self.msg_format_str = msg_format_str
266
270
  self.use_debug_log = use_debug_log
267
271
 
268
272
  async def dispatch(self, request: Request, call_next) -> Response:
269
- _logger = logger.opt(colors=True, record=True)
273
+ _logger = logger.opt(colors=True, record=True).bind(
274
+ disable_all_std_handler=True
275
+ )
270
276
 
271
277
  _http_info: dict[str, Any] = {}
272
278
  if hasattr(request.state, "http_info") and isinstance(
@@ -276,11 +282,15 @@ class HttpAccessLogMiddleware(BaseHTTPMiddleware):
276
282
 
277
283
  # Debug log:
278
284
  if self.use_debug_log:
279
- _debug_msg = self.debug_format_str.format(**_http_info)
285
+ _debug_msg = self.debug_msg_format_str.format(**_http_info)
280
286
 
281
- # _logger.debug(_debug_msg)
287
+ # _logger.bind(
288
+ # http_info=_http_info, disable_http_all_file_handlers=True
289
+ # ).debug(_debug_msg)
282
290
  await run_in_threadpool(
283
- _logger.debug,
291
+ _logger.bind(
292
+ http_info=_http_info, disable_http_all_file_handlers=True
293
+ ).debug,
284
294
  _debug_msg,
285
295
  )
286
296
  # Debug log
@@ -296,26 +306,28 @@ class HttpAccessLogMiddleware(BaseHTTPMiddleware):
296
306
 
297
307
  # Http access log:
298
308
  _LEVEL = "INFO"
299
- _format_str = self.format_str
309
+ _msg_format_str = self.msg_format_str
300
310
  if _http_info["status_code"] < 200:
301
311
  _LEVEL = "DEBUG"
302
- _format_str = f'<d>{_format_str.replace("{status_code}", "<n><b><k>{status_code}</k></b></n>")}</d>'
312
+ _msg_format_str = f'<d>{_msg_format_str.replace("{status_code}", "<n><b><k>{status_code}</k></b></n>")}</d>'
303
313
  elif (200 <= _http_info["status_code"]) and (_http_info["status_code"] < 300):
304
314
  _LEVEL = "SUCCESS"
305
- _format_str = f'<w>{_format_str.replace("{status_code}", "<lvl>{status_code}</lvl>")}</w>'
315
+ _msg_format_str = f'<w>{_msg_format_str.replace("{status_code}", "<lvl>{status_code}</lvl>")}</w>'
306
316
  elif (300 <= _http_info["status_code"]) and (_http_info["status_code"] < 400):
307
317
  _LEVEL = "INFO"
308
- _format_str = f'<d>{_format_str.replace("{status_code}", "<n><b><c>{status_code}</c></b></n>")}</d>'
318
+ _msg_format_str = f'<d>{_msg_format_str.replace("{status_code}", "<n><b><c>{status_code}</c></b></n>")}</d>'
309
319
  elif (400 <= _http_info["status_code"]) and (_http_info["status_code"] < 500):
310
320
  _LEVEL = "WARNING"
311
- _format_str = _format_str.replace("{status_code}", "<r>{status_code}</r>")
321
+ _msg_format_str = _msg_format_str.replace(
322
+ "{status_code}", "<r>{status_code}</r>"
323
+ )
312
324
  elif 500 <= _http_info["status_code"]:
313
325
  _LEVEL = "ERROR"
314
- _format_str = (
315
- f'{_format_str.replace("{status_code}", "<n>{status_code}</n>")}'
326
+ _msg_format_str = (
327
+ f'{_msg_format_str.replace("{status_code}", "<n>{status_code}</n>")}'
316
328
  )
317
329
 
318
- _msg = _format_str.format(**_http_info)
330
+ _msg = _msg_format_str.format(**_http_info)
319
331
  # _logger.bind(http_info=_http_info).log(_LEVEL, _msg)
320
332
  await run_in_threadpool(_logger.bind(http_info=_http_info).log, _LEVEL, _msg)
321
333
  # Http access log
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beans_logging_fastapi
3
- Version: 3.0.0
4
- Summary: This is a middleware for FastAPI HTTP access logs. It is based on 'beans-logging' package.
3
+ Version: 4.0.1
4
+ Summary: This is a HTTP access log module for FastAPI based on 'beans-logging' package.
5
5
  Author-email: Batkhuu Byambajav <batkhuu10@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bybatkhuu/module-fastapi-logging
7
7
  Project-URL: Documentation, https://fastapi-logging-docs.bybatkhuu.dev
@@ -22,7 +22,7 @@ Requires-Python: <4.0,>=3.10
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE.txt
24
24
  Requires-Dist: fastapi<1.0.0,>=0.99.1
25
- Requires-Dist: beans-logging<9.0.0,>=8.0.2
25
+ Requires-Dist: beans-logging<10.0.0,>=9.0.2
26
26
  Provides-Extra: test
27
27
  Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "test"
28
28
  Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "test"
@@ -55,7 +55,7 @@ Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "dev"
55
55
  Requires-Dist: mike<3.0.0,>=2.1.3; extra == "dev"
56
56
  Requires-Dist: pyright<2.0.0,>=1.1.392; extra == "dev"
57
57
  Requires-Dist: pre-commit<5.0.0,>=4.0.1; extra == "dev"
58
- Requires-Dist: uvicorn[standard]<1.0.0,>=0.23.0; extra == "dev"
58
+ Requires-Dist: fastapi[standard]<1.0.0,>=0.99.1; extra == "dev"
59
59
  Dynamic: license-file
60
60
 
61
61
  # FastAPI Logging (beans-logging-fastapi)
@@ -64,7 +64,7 @@ Dynamic: license-file
64
64
  [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bybatkhuu/module-fastapi-logging/2.build-publish.yml?logo=GitHub)](https://github.com/bybatkhuu/module-fastapi-logging/actions/workflows/2.build-publish.yml)
65
65
  [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/bybatkhuu/module-fastapi-logging?logo=GitHub&color=blue)](https://github.com/bybatkhuu/module-fastapi-logging/releases)
66
66
 
67
- This is a HTTP access logging module for **FastAPI** based on **'beans-logging'** package.
67
+ This is a HTTP access log module for **FastAPI** based on **'beans-logging'** package.
68
68
 
69
69
  ## ✨ Features
70
70
 
@@ -408,24 +408,24 @@ uvicorn main:app --host=0.0.0.0 --port=8000
408
408
  **Output**:
409
409
 
410
410
  ```txt
411
- [2026-01-01 12:00:00.907 +09:00 | TRACE | beans_logging.intercepters:96]: Intercepted modules: ['concurrent.futures', 'potato_util', 'watchfiles.watcher', 'potato_util.io._sync', 'concurrent', 'uvicorn', 'fastapi', 'uvicorn.error', 'dotenv.main', 'watchfiles.main', 'asyncio', 'dotenv', 'potato_util._base', 'potato_util.io', 'watchfiles']; Muted modules: ['uvicorn.access'];
412
- [2026-01-01 12:00:00.908 +09:00 | INFO | uvicorn.server:84]: Started server process [64590]
413
- [2026-01-01 12:00:00.909 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
414
- [2026-01-01 12:00:00.909 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
415
- [2026-01-01 12:00:00.909 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
416
- [2026-01-01 12:00:00.909 +09:00 | INFO | lifespan:21]: Preparing to startup...
417
- [2026-01-01 12:00:00.909 +09:00 | OK | lifespan:24]: Finished preparation to startup.
418
- [2026-01-01 12:00:00.909 +09:00 | INFO | lifespan:25]: Version: 0.0.0
419
- [2026-01-01 12:00:00.909 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
420
- [2026-01-01 12:00:00.911 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
421
- [2026-01-01 12:00:01.582 +09:00 | DEBUG | anyio._backends._asyncio:986]: [c433596f728744aaa1cde63399dd3995] 127.0.0.1 - "GET / HTTP/1.1"
422
- [2026-01-01 12:00:01.586 +09:00 | OK | anyio._backends._asyncio:986]: [c433596f728744aaa1cde63399dd3995] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 3.1ms
423
- ^C[2026-01-01 12:00:02.074 +09:00 | INFO | uvicorn.server:264]: Shutting down
424
- [2026-01-01 12:00:02.177 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
425
- [2026-01-01 12:00:02.178 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
426
- [2026-01-01 12:00:02.179 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
427
- [2026-01-01 12:00:02.179 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
428
- [2026-01-01 12:00:02.180 +09:00 | INFO | uvicorn.server:94]: Finished server process [64590]
411
+ [2026-01-01 12:00:00.002 +09:00 | TRACE | beans_logging.intercepters:96]: Intercepted modules: ['uvicorn', 'potato_util', 'fastapi', 'uvicorn.error', 'watchfiles.watcher', 'concurrent.futures', 'watchfiles', 'asyncio', 'concurrent', 'potato_util._base', 'dotenv', 'dotenv.main', 'watchfiles.main', 'potato_util.io', 'potato_util.io._sync']; Muted modules: ['uvicorn.access'];
412
+ [2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.server:84]: Started server process [88375]
413
+ [2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
414
+ [2026-01-01 12:00:00.004 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
415
+ [2026-01-01 12:00:00.004 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
416
+ [2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:21]: Preparing to startup...
417
+ [2026-01-01 12:00:00.004 +09:00 | OK | lifespan:24]: Finished preparation to startup.
418
+ [2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:25]: Version: 0.0.0
419
+ [2026-01-01 12:00:00.005 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
420
+ [2026-01-01 12:00:00.006 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
421
+ [2026-01-01 12:00:01.775 +09:00 | DEBUG ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1"
422
+ [2026-01-01 12:00:01.783 +09:00 | OK ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 5.7ms
423
+ ^C[2026-01-01 12:00:02.368 +09:00 | INFO | uvicorn.server:264]: Shutting down
424
+ [2026-01-01 12:00:02.470 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
425
+ [2026-01-01 12:00:02.472 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
426
+ [2026-01-01 12:00:02.472 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
427
+ [2026-01-01 12:00:02.473 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
428
+ [2026-01-01 12:00:02.474 +09:00 | INFO | uvicorn.server:94]: Finished server process [88375]
429
429
  ```
430
430
 
431
431
  👍
@@ -450,12 +450,12 @@ logger:
450
450
  rotate_time: "00:00:00"
451
451
  retention: 90
452
452
  encoding: utf8
453
- custom_serialize: false
453
+ use_custom_serialize: false
454
454
  http:
455
455
  std:
456
- format_str: '<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'
457
- err_format_str: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
458
- debug_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
456
+ msg_format_str: '<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'
457
+ err_msg_format_str: '<n><w>[{request_id}]</w></n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
458
+ debug_msg_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
459
459
  file:
460
460
  format_str: '{client_host} {request_id} {user_id} [{datetime}] "{method} {url_path} HTTP/{http_version}" {status_code} {content_length} "{h_referer}" "{h_user_agent}" {response_time}'
461
461
  tz: localtime
@@ -469,45 +469,50 @@ logger:
469
469
  include_modules: []
470
470
  mute_modules: [uvicorn.access]
471
471
  handlers:
472
- default.all.std_handler:
472
+ all_std_handler:
473
473
  enabled: true
474
474
  h_type: STD
475
475
  format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> | <w>{name}:{line}</w>]: <level>{message}</level>"
476
476
  colorize: true
477
- default.all.file_handler:
477
+ all_file_handler:
478
478
  enabled: true
479
479
  h_type: FILE
480
480
  sink: "{app_name}.all.log"
481
- default.err.file_handler:
481
+ err_file_handler:
482
482
  enabled: true
483
483
  h_type: FILE
484
484
  sink: "{app_name}.err.log"
485
485
  error: true
486
- default.all.json_handler:
486
+ all_json_handler:
487
487
  enabled: true
488
488
  h_type: FILE
489
489
  sink: "json/{app_name}.all.json.log"
490
490
  serialize: true
491
- default.err.json_handler:
491
+ err_json_handler:
492
492
  enabled: true
493
493
  h_type: FILE
494
494
  sink: "json/{app_name}.err.json.log"
495
495
  serialize: true
496
496
  error: true
497
- http.access.file_handler:
497
+ http_access_std_handler:
498
+ enabled: true
499
+ h_type: STD
500
+ format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> ]: <level>{message}</level>"
501
+ colorize: true
502
+ http_access_file_handler:
498
503
  enabled: true
499
504
  h_type: FILE
500
505
  sink: "http/{app_name}.http-access.log"
501
- http.err.file_handler:
506
+ http_err_file_handler:
502
507
  enabled: true
503
508
  h_type: FILE
504
509
  sink: "http/{app_name}.http-err.log"
505
510
  error: true
506
- http.access.json_handler:
511
+ http_access_json_handler:
507
512
  enabled: true
508
513
  h_type: FILE
509
514
  sink: "http.json/{app_name}.http-access.json.log"
510
- http.err.json_handler:
515
+ http_err_json_handler:
511
516
  enabled: true
512
517
  h_type: FILE
513
518
  sink: "http.json/{app_name}.http-err.json.log"
@@ -1,5 +1,5 @@
1
1
  fastapi<1.0.0,>=0.99.1
2
- beans-logging<9.0.0,>=8.0.2
2
+ beans-logging<10.0.0,>=9.0.2
3
3
 
4
4
  [build]
5
5
  setuptools<81.0.0,>=70.3.0
@@ -23,7 +23,7 @@ mkdocstrings[python]<2.0.0,>=0.24.3
23
23
  mike<3.0.0,>=2.1.3
24
24
  pyright<2.0.0,>=1.1.392
25
25
  pre-commit<5.0.0,>=4.0.1
26
- uvicorn[standard]<1.0.0,>=0.23.0
26
+ fastapi[standard]<1.0.0,>=0.99.1
27
27
 
28
28
  [docs]
29
29
  pylint<5.0.0,>=3.0.4
@@ -1,2 +0,0 @@
1
- fastapi>=0.99.1,<1.0.0
2
- beans-logging>=8.0.2,<9.0.0
@@ -1 +0,0 @@
1
- __version__ = "3.0.0"
@@ -1,12 +0,0 @@
1
- HTTP_ACCESS_FILE_HANDLER_NAME = "http.access.file_handler"
2
- HTTP_ERR_FILE_HANDLER_NAME = "http.err.file_handler"
3
- HTTP_ACCESS_JSON_HANDLER_NAME = "http.access.json_handler"
4
- HTTP_ERR_JSON_HANDLER_NAME = "http.err.json_handler"
5
-
6
-
7
- __all__ = [
8
- "HTTP_ACCESS_FILE_HANDLER_NAME",
9
- "HTTP_ERR_FILE_HANDLER_NAME",
10
- "HTTP_ACCESS_JSON_HANDLER_NAME",
11
- "HTTP_ERR_JSON_HANDLER_NAME",
12
- ]
@@ -1,30 +0,0 @@
1
- from typing import TYPE_CHECKING
2
-
3
- if TYPE_CHECKING:
4
- from loguru import Record
5
-
6
- from beans_logging.filters import use_all_filter
7
-
8
-
9
- def use_http_filter(record: "Record") -> bool:
10
- """Filter message only for http access log handler by checking 'http_info' key in extra.
11
-
12
- Args:
13
- record (Record, required): Log record as dictionary.
14
-
15
- Returns:
16
- bool: True if record has 'http_info' key in extra, False otherwise.
17
- """
18
-
19
- if not use_all_filter(record):
20
- return False
21
-
22
- if "http_info" not in record["extra"]:
23
- return False
24
-
25
- return True
26
-
27
-
28
- __all__ = [
29
- "use_http_filter",
30
- ]