beans-logging-fastapi 3.0.0__py3-none-any.whl → 4.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- beans_logging_fastapi/__version__.py +1 -1
- beans_logging_fastapi/_async.py +7 -7
- beans_logging_fastapi/_core.py +11 -8
- beans_logging_fastapi/config.py +14 -5
- beans_logging_fastapi/constants.py +15 -4
- beans_logging_fastapi/filters.py +46 -4
- beans_logging_fastapi/formats.py +2 -2
- beans_logging_fastapi/middlewares.py +36 -24
- {beans_logging_fastapi-3.0.0.dist-info → beans_logging_fastapi-4.0.0.dist-info}/METADATA +41 -36
- beans_logging_fastapi-4.0.0.dist-info/RECORD +14 -0
- beans_logging_fastapi-3.0.0.dist-info/RECORD +0 -14
- {beans_logging_fastapi-3.0.0.dist-info → beans_logging_fastapi-4.0.0.dist-info}/WHEEL +0 -0
- {beans_logging_fastapi-3.0.0.dist-info → beans_logging_fastapi-4.0.0.dist-info}/licenses/LICENSE.txt +0 -0
- {beans_logging_fastapi-3.0.0.dist-info → beans_logging_fastapi-4.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "
|
|
1
|
+
__version__ = "4.0.0"
|
beans_logging_fastapi/_async.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
23
|
-
status_code
|
|
24
|
-
|
|
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 =
|
|
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
|
beans_logging_fastapi/_core.py
CHANGED
|
@@ -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
|
|
21
|
-
from .formats import http_file_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
|
-
|
|
60
|
-
|
|
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
|
|
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_ =
|
|
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_ =
|
|
82
|
-
_handler.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
|
beans_logging_fastapi/config.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
]
|
|
5
14
|
|
|
6
15
|
|
|
7
16
|
__all__ = [
|
|
17
|
+
"HTTP_ACCESS_STD_HANDLER_NAME",
|
|
8
18
|
"HTTP_ACCESS_FILE_HANDLER_NAME",
|
|
9
19
|
"HTTP_ERR_FILE_HANDLER_NAME",
|
|
10
20
|
"HTTP_ACCESS_JSON_HANDLER_NAME",
|
|
11
21
|
"HTTP_ERR_JSON_HANDLER_NAME",
|
|
22
|
+
"HTTP_HANDLER_NAMES",
|
|
12
23
|
]
|
beans_logging_fastapi/filters.py
CHANGED
|
@@ -3,10 +3,12 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
if TYPE_CHECKING:
|
|
4
4
|
from loguru import Record
|
|
5
5
|
|
|
6
|
-
from beans_logging.filters import
|
|
6
|
+
from beans_logging.filters import all_handlers_filter
|
|
7
7
|
|
|
8
|
+
from .constants import HTTP_ACCESS_STD_HANDLER_NAME
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
def http_filter(record: "Record") -> bool:
|
|
10
12
|
"""Filter message only for http access log handler by checking 'http_info' key in extra.
|
|
11
13
|
|
|
12
14
|
Args:
|
|
@@ -16,7 +18,7 @@ def use_http_filter(record: "Record") -> bool:
|
|
|
16
18
|
bool: True if record has 'http_info' key in extra, False otherwise.
|
|
17
19
|
"""
|
|
18
20
|
|
|
19
|
-
if not
|
|
21
|
+
if not all_handlers_filter(record):
|
|
20
22
|
return False
|
|
21
23
|
|
|
22
24
|
if "http_info" not in record["extra"]:
|
|
@@ -25,6 +27,46 @@ def use_http_filter(record: "Record") -> bool:
|
|
|
25
27
|
return True
|
|
26
28
|
|
|
27
29
|
|
|
30
|
+
def http_std_filter(record: "Record") -> bool:
|
|
31
|
+
"""Filter message only for http std log handler.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
record (Record, required): Log record as dictionary.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
bool: True if record does not have 'disable_{HTTP_ACCESS_STD_HANDLER_NAME}' key in extra, False otherwise.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
if not http_filter(record):
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
if record["extra"].get(f"disable_{HTTP_ACCESS_STD_HANDLER_NAME}", False):
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def http_all_file_filter(record: "Record") -> bool:
|
|
50
|
+
"""Filter message only for http file log handler.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
record (Record, required): Log record as dictionary.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
bool: True if record does not have 'disable_http_all_file_handlers' key in extra, False otherwise.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
if not http_filter(record):
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
if record["extra"].get("disable_http_all_file_handlers", False):
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
|
|
28
68
|
__all__ = [
|
|
29
|
-
"
|
|
69
|
+
"http_filter",
|
|
70
|
+
"http_std_filter",
|
|
71
|
+
"http_all_file_filter",
|
|
30
72
|
]
|
beans_logging_fastapi/formats.py
CHANGED
|
@@ -62,7 +62,7 @@ def http_file_format(
|
|
|
62
62
|
return "{extra[http_message]}\n"
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def
|
|
65
|
+
def http_json_format(record: "Record") -> str:
|
|
66
66
|
"""Http access json log file format.
|
|
67
67
|
|
|
68
68
|
Args:
|
|
@@ -91,5 +91,5 @@ def http_file_json_format(record: "Record") -> str:
|
|
|
91
91
|
|
|
92
92
|
__all__ = [
|
|
93
93
|
"http_file_format",
|
|
94
|
-
"
|
|
94
|
+
"http_json_format",
|
|
95
95
|
]
|
|
@@ -235,20 +235,24 @@ class HttpAccessLogMiddleware(BaseHTTPMiddleware):
|
|
|
235
235
|
BaseHTTPMiddleware: Base HTTP middleware class from starlette.
|
|
236
236
|
|
|
237
237
|
Attributes:
|
|
238
|
-
|
|
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
|
-
|
|
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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
-
|
|
251
|
-
|
|
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
|
-
|
|
260
|
-
|
|
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.
|
|
265
|
-
self.
|
|
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.
|
|
285
|
+
_debug_msg = self.debug_msg_format_str.format(**_http_info)
|
|
280
286
|
|
|
281
|
-
# _logger.
|
|
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.
|
|
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
|
-
|
|
309
|
+
_msg_format_str = self.msg_format_str
|
|
300
310
|
if _http_info["status_code"] < 200:
|
|
301
311
|
_LEVEL = "DEBUG"
|
|
302
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
315
|
-
f'{
|
|
326
|
+
_msg_format_str = (
|
|
327
|
+
f'{_msg_format_str.replace("{status_code}", "<n>{status_code}</n>")}'
|
|
316
328
|
)
|
|
317
329
|
|
|
318
|
-
_msg =
|
|
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:
|
|
4
|
-
Summary: This is a
|
|
3
|
+
Version: 4.0.0
|
|
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<
|
|
25
|
+
Requires-Dist: beans-logging<10.0.0,>=9.0.0
|
|
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:
|
|
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
|
[](https://github.com/bybatkhuu/module-fastapi-logging/actions/workflows/2.build-publish.yml)
|
|
65
65
|
[](https://github.com/bybatkhuu/module-fastapi-logging/releases)
|
|
66
66
|
|
|
67
|
-
This is a HTTP access
|
|
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.
|
|
412
|
-
[2026-01-01 12:00:00.
|
|
413
|
-
[2026-01-01 12:00:00.
|
|
414
|
-
[2026-01-01 12:00:00.
|
|
415
|
-
[2026-01-01 12:00:00.
|
|
416
|
-
[2026-01-01 12:00:00.
|
|
417
|
-
[2026-01-01 12:00:00.
|
|
418
|
-
[2026-01-01 12:00:00.
|
|
419
|
-
[2026-01-01 12:00:00.
|
|
420
|
-
[2026-01-01 12:00:00.
|
|
421
|
-
[2026-01-01 12:00:01.
|
|
422
|
-
[2026-01-01 12:00:01.
|
|
423
|
-
^C[2026-01-01 12:00:02.
|
|
424
|
-
[2026-01-01 12:00:02.
|
|
425
|
-
[2026-01-01 12:00:02.
|
|
426
|
-
[2026-01-01 12:00:02.
|
|
427
|
-
[2026-01-01 12:00:02.
|
|
428
|
-
[2026-01-01 12:00:02.
|
|
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
|
-
|
|
453
|
+
use_custom_serialize: false
|
|
454
454
|
http:
|
|
455
455
|
std:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
|
|
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
|
-
|
|
477
|
+
all_file_handler:
|
|
478
478
|
enabled: true
|
|
479
479
|
h_type: FILE
|
|
480
480
|
sink: "{app_name}.all.log"
|
|
481
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
beans_logging_fastapi/__init__.py,sha256=5nnhUvYdtaMSZ1t549nhYfxOzcKsC4YPx8nEqJWfZYw,225
|
|
2
|
+
beans_logging_fastapi/__version__.py,sha256=SQa6Ci17DORmGXi_wkOW9pPlUojF-qtjH6NV1WOThsU,22
|
|
3
|
+
beans_logging_fastapi/_async.py,sha256=8WncsgrofroUm1z8kgUkfZYP9vwrr9Lri31PrR0NTko,3495
|
|
4
|
+
beans_logging_fastapi/_core.py,sha256=Tsc99l6i0Cryrh-UJ-uUfW5FG1O3PtQjE9QNBuJ3Eyk,2915
|
|
5
|
+
beans_logging_fastapi/config.py,sha256=GvEoPBexT0HXFhqd1vbiJ-XCwkBPwPqYmL33tJTGkK0,5687
|
|
6
|
+
beans_logging_fastapi/constants.py,sha256=SgiS27cpih3QHejlf6db3ZnFBEEzJzC0T62l8B0ZXxs,695
|
|
7
|
+
beans_logging_fastapi/filters.py,sha256=p6DgcmSByDwkw0i30AYczi26nPxWsPRfzaY8LhN1Q1I,1681
|
|
8
|
+
beans_logging_fastapi/formats.py,sha256=7zr-EIYg9vRs1zlhY9If68X9rC0xDBNG9Xc7QH9_elg,2590
|
|
9
|
+
beans_logging_fastapi/middlewares.py,sha256=ZOmp5oCg9RqnetSOBvwdQlOy87ix76ayS6HosbPG62k,14158
|
|
10
|
+
beans_logging_fastapi-4.0.0.dist-info/licenses/LICENSE.txt,sha256=CUTK-r0BWIg1r0bBiemAcMhakgV0N7HuRhw6rQ-A9A4,1074
|
|
11
|
+
beans_logging_fastapi-4.0.0.dist-info/METADATA,sha256=qOii9qAR3j67H8M3A1CW3-n4bfKTDFGNAvhwzD3FEYc,17459
|
|
12
|
+
beans_logging_fastapi-4.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
+
beans_logging_fastapi-4.0.0.dist-info/top_level.txt,sha256=PXoqVo9HGfyd81gDi3D2mXMYPM9JKITL0ycFftJxlhw,22
|
|
14
|
+
beans_logging_fastapi-4.0.0.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
beans_logging_fastapi/__init__.py,sha256=5nnhUvYdtaMSZ1t549nhYfxOzcKsC4YPx8nEqJWfZYw,225
|
|
2
|
-
beans_logging_fastapi/__version__.py,sha256=EPmgXOdWKks5S__ZMH7Nu6xpAeVrZpfxaFy4pykuyeI,22
|
|
3
|
-
beans_logging_fastapi/_async.py,sha256=IcoQPeBfZwPLt-WBJBpc7g5pELh6plf7VYUel2KyM_c,3478
|
|
4
|
-
beans_logging_fastapi/_core.py,sha256=NUpQGvuLw5YlRNTvssBo4aqrE0lia4nhL1aDahZXncU,2744
|
|
5
|
-
beans_logging_fastapi/config.py,sha256=gt9Kh0-MOZdf0LMGV5gbyYucoTkF8He5QceUP-9vS8U,5298
|
|
6
|
-
beans_logging_fastapi/constants.py,sha256=pRsgi1pqkEDMKmSWDQeK72TSXiuVkJaEMTOUeB82E5A,382
|
|
7
|
-
beans_logging_fastapi/filters.py,sha256=hBhHqCWJr7c2CA7uDAje8R8x9RtpCcBHZSC6xuXLYDs,622
|
|
8
|
-
beans_logging_fastapi/formats.py,sha256=ENfCB54ftUZZFj5J9kKCsdCkeqzStG3l0_9vLBLi8Oc,2600
|
|
9
|
-
beans_logging_fastapi/middlewares.py,sha256=ToUS4jPUPcZHTr_d7DWLjfBI-E9FrspasRqkc4Gyg2M,13676
|
|
10
|
-
beans_logging_fastapi-3.0.0.dist-info/licenses/LICENSE.txt,sha256=CUTK-r0BWIg1r0bBiemAcMhakgV0N7HuRhw6rQ-A9A4,1074
|
|
11
|
-
beans_logging_fastapi-3.0.0.dist-info/METADATA,sha256=iL3NjWvF6KMVxaO7RytgEMuGxMoWAQBlyXqF0lsaBdM,17344
|
|
12
|
-
beans_logging_fastapi-3.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
-
beans_logging_fastapi-3.0.0.dist-info/top_level.txt,sha256=PXoqVo9HGfyd81gDi3D2mXMYPM9JKITL0ycFftJxlhw,22
|
|
14
|
-
beans_logging_fastapi-3.0.0.dist-info/RECORD,,
|
|
File without changes
|
{beans_logging_fastapi-3.0.0.dist-info → beans_logging_fastapi-4.0.0.dist-info}/licenses/LICENSE.txt
RENAMED
|
File without changes
|
{beans_logging_fastapi-3.0.0.dist-info → beans_logging_fastapi-4.0.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|