beans-logging-fastapi 2.0.0__tar.gz → 3.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 (33) hide show
  1. {beans_logging_fastapi-2.0.0/src/beans_logging_fastapi.egg-info → beans_logging_fastapi-3.0.0}/PKG-INFO +233 -144
  2. beans_logging_fastapi-3.0.0/README.md +526 -0
  3. beans_logging_fastapi-3.0.0/requirements/requirements.dev.txt +3 -0
  4. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/requirements/requirements.test.txt +0 -1
  5. beans_logging_fastapi-3.0.0/requirements.txt +2 -0
  6. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/__init__.py +13 -0
  7. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/__version__.py +1 -0
  8. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_async_log.py → beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/_async.py +3 -3
  9. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/_core.py +90 -0
  10. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/config.py +168 -0
  11. beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/constants.py +12 -0
  12. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_formats.py → beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/formats.py +5 -5
  13. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_middlewares.py → beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/middlewares.py +97 -0
  14. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0/src/beans_logging_fastapi.egg-info}/PKG-INFO +233 -144
  15. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/src/beans_logging_fastapi.egg-info/SOURCES.txt +7 -6
  16. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/src/beans_logging_fastapi.egg-info/requires.txt +2 -1
  17. beans_logging_fastapi-2.0.0/README.md +0 -438
  18. beans_logging_fastapi-2.0.0/requirements/requirements.dev.txt +0 -6
  19. beans_logging_fastapi-2.0.0/requirements.txt +0 -2
  20. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/__init__.py +0 -31
  21. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/__version__.py +0 -1
  22. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_base.py +0 -107
  23. beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_handlers.py +0 -96
  24. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/.python-version +0 -0
  25. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/LICENSE.txt +0 -0
  26. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/pyproject.toml +0 -0
  27. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/requirements/requirements.build.txt +0 -0
  28. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/requirements/requirements.docs.txt +0 -0
  29. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/setup.cfg +0 -0
  30. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/setup.py +0 -0
  31. /beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_filters.py → /beans_logging_fastapi-3.0.0/src/beans_logging_fastapi/filters.py +0 -0
  32. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/src/beans_logging_fastapi.egg-info/dependency_links.txt +0 -0
  33. {beans_logging_fastapi-2.0.0 → beans_logging_fastapi-3.0.0}/src/beans_logging_fastapi.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beans_logging_fastapi
3
- Version: 2.0.0
3
+ Version: 3.0.0
4
4
  Summary: This is a middleware for FastAPI HTTP access logs. It is 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
@@ -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<8.0.0,>=7.1.0
25
+ Requires-Dist: beans-logging<9.0.0,>=8.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,6 +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
59
  Dynamic: license-file
59
60
 
60
61
  # FastAPI Logging (beans-logging-fastapi)
@@ -63,12 +64,15 @@ Dynamic: license-file
63
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)
64
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)
65
66
 
66
- This is a middleware for FastAPI HTTP access logs. It is based on **'beans-logging'** package.
67
+ This is a HTTP access logging module for **FastAPI** based on **'beans-logging'** package.
67
68
 
68
69
  ## ✨ Features
69
70
 
70
71
  - **Logger** based on **'beans-logging'** package
71
72
  - **FastAPI** HTTP access logging **middleware**
73
+ - HTTP access log as structured JSON format
74
+ - Predefined **configuration** for HTTP access logs
75
+ - Easy to **install** and **use**
72
76
 
73
77
  ---
74
78
 
@@ -160,28 +164,35 @@ To use `beans_logging_fastapi`:
160
164
  ```yaml
161
165
  logger:
162
166
  app_name: "fastapi-app"
167
+ default:
168
+ level:
169
+ base: TRACE
170
+ http:
171
+ std:
172
+ 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'
173
+ 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>'
174
+ debug_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
175
+ file:
176
+ 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}'
177
+ tz: "localtime"
178
+ headers:
179
+ has_proxy: false
180
+ has_cf: false
163
181
  intercept:
164
182
  mute_modules: ["uvicorn.access"]
165
183
  handlers:
166
- default.all.file_handler:
184
+ http.access.file_handler:
167
185
  enabled: true
168
- default.err.file_handler:
186
+ sink: "http/{app_name}.http-access.log"
187
+ http.err.file_handler:
169
188
  enabled: true
170
- default.all.json_handler:
189
+ sink: "http/{app_name}.http-err.log"
190
+ http.access.json_handler:
171
191
  enabled: true
172
- default.err.json_handler:
192
+ sink: "http.json/{app_name}.http-access.json.log"
193
+ http.err.json_handler:
173
194
  enabled: true
174
- extra:
175
- http_std_debug_format: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
176
- 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'
177
- http_file_enabled: true
178
- http_file_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}'
179
- http_file_tz: "localtime"
180
- http_log_path: "http/{app_name}.http.access.log"
181
- http_err_path: "http/{app_name}.http.err.log"
182
- http_json_enabled: true
183
- http_json_path: "http.json/{app_name}.http.json.access.log"
184
- http_json_err_path: "http.json/{app_name}.http.json.err.log"
195
+ sink: "http.json/{app_name}.http-err.json.log"
185
196
  ```
186
197
 
187
198
  [**`.env`**](./examples/.env):
@@ -191,140 +202,197 @@ ENV=development
191
202
  DEBUG=true
192
203
  ```
193
204
 
194
- [**`logger.py`**](./examples/logger.py):
205
+ [**`config.py`**](./examples/config.py):
195
206
 
196
207
  ```python
197
- from typing import TYPE_CHECKING
208
+ import os
198
209
 
199
- if TYPE_CHECKING:
200
- from loguru import Record
210
+ from pydantic_settings import BaseSettings
201
211
 
202
- from beans_logging import Logger, LoggerLoader
203
- from beans_logging_fastapi import (
204
- add_http_file_handler,
205
- add_http_file_json_handler,
206
- http_file_format,
207
- )
212
+ from potato_util import io as io_utils
213
+ from beans_logging_fastapi import LoggerConfigPM
208
214
 
209
- logger_loader = LoggerLoader()
210
- logger: Logger = logger_loader.load()
211
215
 
216
+ _config_path = os.path.join(os.getcwd(), "configs", "logger.yml")
217
+ _config_data = {}
218
+ if os.path.isfile(_config_path):
219
+ _config_data = io_utils.read_config_file(config_path=_config_path)
212
220
 
213
- def _http_file_format(record: "Record") -> str:
214
- _format = http_file_format(
215
- record=record,
216
- msg_format=logger_loader.config.extra.http_file_format, # type: ignore
217
- tz=logger_loader.config.extra.http_file_tz, # type: ignore
218
- )
219
- return _format
220
221
 
222
+ class MainConfig(BaseSettings):
223
+ logger: LoggerConfigPM = LoggerConfigPM()
221
224
 
222
- if logger_loader.config.extra.http_file_enabled: # type: ignore
223
- add_http_file_handler(
224
- logger_loader=logger_loader,
225
- log_path=logger_loader.config.extra.http_log_path, # type: ignore
226
- err_path=logger_loader.config.extra.http_err_path, # type: ignore
227
- formatter=_http_file_format,
228
- )
229
225
 
230
- if logger_loader.config.extra.http_json_enabled: # type: ignore
231
- add_http_file_json_handler(
232
- logger_loader=logger_loader,
233
- log_path=logger_loader.config.extra.http_json_path, # type: ignore
234
- err_path=logger_loader.config.extra.http_json_err_path, # type: ignore
235
- )
226
+ config = MainConfig(**_config_data)
236
227
 
237
228
 
238
229
  __all__ = [
239
- "logger",
240
- "logger_loader",
230
+ "MainConfig",
231
+ "config",
241
232
  ]
242
233
  ```
243
234
 
244
- [**`main.py`**](./examples/main.py):
235
+ [**`logger.py`**](./examples/logger.py):
245
236
 
246
237
  ```python
247
- #!/usr/bin/env python
248
-
249
- from typing import Union
250
- from contextlib import asynccontextmanager
251
-
252
- import uvicorn
253
- from dotenv import load_dotenv
254
- from fastapi import FastAPI, HTTPException
255
- from fastapi.responses import RedirectResponse
256
-
257
- load_dotenv()
258
-
259
- from beans_logging_fastapi import (
260
- HttpAccessLogMiddleware,
261
- RequestHTTPInfoMiddleware,
262
- ResponseHTTPInfoMiddleware,
263
- )
264
-
265
- from logger import logger, logger_loader
266
- from __version__ import __version__
238
+ from beans_logging_fastapi import logger
267
239
 
240
+ __all__ = [
241
+ "logger",
242
+ ]
243
+ ```
268
244
 
269
- @asynccontextmanager
270
- async def lifespan(app: FastAPI):
271
- logger.info("Preparing to startup...")
272
- logger.success("Finished preparation to startup.")
273
- logger.info(f"API version: {__version__}")
274
-
275
- yield
276
- logger.info("Praparing to shutdown...")
277
- logger.success("Finished preparation to shutdown.")
278
-
245
+ [**`router.py`**](./examples/router.py):
279
246
 
280
- app = FastAPI(lifespan=lifespan, version=__version__)
247
+ ```python
248
+ from pydantic import validate_call
249
+ from fastapi import FastAPI, APIRouter, HTTPException
250
+ from fastapi.responses import RedirectResponse
281
251
 
282
- app.add_middleware(ResponseHTTPInfoMiddleware)
283
- app.add_middleware(
284
- HttpAccessLogMiddleware,
285
- debug_format=logger_loader.config.extra.http_std_debug_format, # type: ignore
286
- msg_format=logger_loader.config.extra.http_std_msg_format, # type: ignore
287
- )
288
- app.add_middleware(
289
- RequestHTTPInfoMiddleware, has_proxy_headers=True, has_cf_headers=True
290
- )
252
+ router = APIRouter()
291
253
 
292
254
 
293
- @app.get("/")
255
+ @router.get("/")
294
256
  def root():
295
257
  return {"Hello": "World"}
296
258
 
297
259
 
298
- @app.get("/items/{item_id}")
299
- def read_item(item_id: int, q: Union[str, None] = None):
260
+ @router.get("/items/{item_id}")
261
+ def read_item(item_id: int, q: str | None = None):
300
262
  return {"item_id": item_id, "q": q}
301
263
 
302
264
 
303
- @app.get("/continue", status_code=100)
265
+ @router.get("/continue", status_code=100)
304
266
  def get_continue():
305
267
  return {}
306
268
 
307
269
 
308
- @app.get("/redirect")
270
+ @router.get("/redirect")
309
271
  def redirect():
310
272
  return RedirectResponse("/")
311
273
 
312
274
 
313
- @app.get("/error")
275
+ @router.get("/error")
314
276
  def error():
315
277
  raise HTTPException(status_code=500)
316
278
 
317
279
 
318
- if __name__ == "__main__":
280
+ @validate_call(config={"arbitrary_types_allowed": True})
281
+ def add_routers(app: FastAPI) -> None:
282
+ """Add routers to FastAPI app.
283
+
284
+ Args:
285
+ app (FastAPI): FastAPI app instance.
286
+ """
287
+
288
+ app.include_router(router)
289
+
290
+ return
291
+
292
+
293
+ __all__ = ["add_routers"]
294
+ ```
295
+
296
+ [**`bootstrap.py`**](./examples/bootstrap.py):
297
+
298
+ ```python
299
+ # Standard libraries
300
+ from typing import Any
301
+ from collections.abc import Callable
302
+
303
+ # Third-party libraries
304
+ import uvicorn
305
+ from uvicorn._types import ASGIApplication
306
+ from pydantic import validate_call
307
+ from fastapi import FastAPI
308
+
309
+ from beans_logging_fastapi import add_logger
310
+
311
+ # Internal modules
312
+ from __version__ import __version__
313
+ from config import config
314
+ from lifespan import lifespan
315
+ from router import add_routers
316
+
317
+
318
+ def create_app() -> FastAPI:
319
+ """Create FastAPI application instance.
320
+
321
+ Returns:
322
+ FastAPI: FastAPI application instance.
323
+ """
324
+
325
+ app = FastAPI(lifespan=lifespan, version=__version__)
326
+
327
+ # Add logger before any other components:
328
+ add_logger(app=app, config=config.logger)
329
+
330
+ # Add any other components after logger:
331
+ add_routers(app=app)
332
+
333
+ return app
334
+
335
+
336
+ @validate_call(config={"arbitrary_types_allowed": True})
337
+ def run_server(
338
+ app: FastAPI | ASGIApplication | Callable[..., Any] | str = "main:app",
339
+ ) -> None:
340
+ """Run uvicorn server.
341
+
342
+ Args:
343
+ app (Union[ASGIApplication, str], optional): ASGI application instance or module path.
344
+ """
345
+
319
346
  uvicorn.run(
320
- app="main:app",
321
- host="0.0.0.0",
347
+ app=app,
348
+ host="0.0.0.0", # nosec B104
322
349
  port=8000,
323
- access_log=False,
350
+ access_log=False, # Disable default uvicorn access log
324
351
  server_header=False,
325
- proxy_headers=True,
352
+ proxy_headers=False,
326
353
  forwarded_allow_ips="*",
327
354
  )
355
+
356
+ return
357
+
358
+
359
+ __all__ = [
360
+ "create_app",
361
+ "run_server",
362
+ ]
363
+ ```
364
+
365
+ [**`main.py`**](./examples/main.py):
366
+
367
+ ```python
368
+ #!/usr/bin/env python
369
+
370
+ # Third-party libraries
371
+ from dotenv import load_dotenv
372
+
373
+ load_dotenv(override=True)
374
+
375
+ # Internal modules
376
+ from bootstrap import create_app, run_server # noqa: E402
377
+ from logger import logger # noqa: E402
378
+
379
+
380
+ app = create_app()
381
+
382
+
383
+ def main() -> None:
384
+ """Main function."""
385
+
386
+ run_server(app=app)
387
+ return
388
+
389
+
390
+ if __name__ == "__main__":
391
+ logger.info("Starting server from 'main.py'...")
392
+ main()
393
+
394
+
395
+ __all__ = ["app"]
328
396
  ```
329
397
 
330
398
  Run the [**`examples`**](./examples):
@@ -340,22 +408,24 @@ uvicorn main:app --host=0.0.0.0 --port=8000
340
408
  **Output**:
341
409
 
342
410
  ```txt
343
- [2025-12-01 00:00:00.735 +09:00 | TRACE | beans_logging._intercept:96]: Intercepted modules: ['potato_util.io', 'concurrent', 'potato_util', 'fastapi', 'uvicorn.error', 'dotenv.main', 'potato_util._base', 'watchfiles.watcher', 'dotenv', 'potato_util.io._sync', 'asyncio', 'uvicorn', 'concurrent.futures', 'watchfiles', 'watchfiles.main']; Muted modules: ['uvicorn.access'];
344
- [2025-12-01 00:00:00.735 +09:00 | INFO | uvicorn.server:84]: Started server process [13580]
345
- [2025-12-01 00:00:00.735 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
346
- [2025-12-01 00:00:00.735 +09:00 | INFO | main:25]: Preparing to startup...
347
- [2025-12-01 00:00:00.735 +09:00 | OK | main:26]: Finished preparation to startup.
348
- [2025-12-01 00:00:00.735 +09:00 | INFO | main:27]: API version: 0.0.0
349
- [2025-12-01 00:00:00.735 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
350
- [2025-12-01 00:00:00.735 +09:00 | INFO | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
351
- [2025-12-01 00:00:00.736 +09:00 | DEBUG | anyio._backends._asyncio:986]: [4386400aab364895ba272f3200d2a778] 127.0.0.1 - "GET / HTTP/1.1"
352
- [2025-12-01 00:00:00.736 +09:00 | OK | anyio._backends._asyncio:986]: [4386400aab364895ba272f3200d2a778] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 0.9ms
353
- ^C[2025-12-01 00:00:00.750 +09:00 | INFO | uvicorn.server:264]: Shutting down
354
- [2025-12-01 00:00:00.750 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
355
- [2025-12-01 00:00:00.750 +09:00 | INFO | main:30]: Praparing to shutdown...
356
- [2025-12-01 00:00:00.750 +09:00 | OK | main:31]: Finished preparation to shutdown.
357
- [2025-12-01 00:00:00.750 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
358
- [2025-12-01 00:00:00.750 +09:00 | INFO | uvicorn.server:94]: Finished server process [13580]
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]
359
429
  ```
360
430
 
361
431
  👍
@@ -368,7 +438,7 @@ uvicorn main:app --host=0.0.0.0 --port=8000
368
438
 
369
439
  ```yaml
370
440
  logger:
371
- # app_name: "app"
441
+ # app_name: fastapi-app
372
442
  default:
373
443
  level:
374
444
  base: INFO
@@ -381,49 +451,68 @@ logger:
381
451
  retention: 90
382
452
  encoding: utf8
383
453
  custom_serialize: false
454
+ http:
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}"'
459
+ file:
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
+ tz: localtime
462
+ headers:
463
+ has_proxy: false
464
+ has_cf: false
384
465
  intercept:
385
466
  enabled: true
386
467
  only_base: false
387
468
  ignore_modules: []
388
469
  include_modules: []
389
- mute_modules: ["uvicorn.access"]
470
+ mute_modules: [uvicorn.access]
390
471
  handlers:
391
472
  default.all.std_handler:
392
- type: STD
473
+ enabled: true
474
+ h_type: STD
393
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>"
394
476
  colorize: true
395
- enabled: true
396
477
  default.all.file_handler:
397
- type: FILE
398
- sink: "{app_name}.all.log"
399
478
  enabled: true
479
+ h_type: FILE
480
+ sink: "{app_name}.all.log"
400
481
  default.err.file_handler:
401
- type: FILE
482
+ enabled: true
483
+ h_type: FILE
402
484
  sink: "{app_name}.err.log"
403
485
  error: true
404
- enabled: true
405
486
  default.all.json_handler:
406
- type: FILE
407
- sink: "json/{app_name}.json.all.log"
408
- serialize: true
409
487
  enabled: true
488
+ h_type: FILE
489
+ sink: "json/{app_name}.all.json.log"
490
+ serialize: true
410
491
  default.err.json_handler:
411
- type: FILE
412
- sink: "json/{app_name}.json.err.log"
492
+ enabled: true
493
+ h_type: FILE
494
+ sink: "json/{app_name}.err.json.log"
413
495
  serialize: true
414
496
  error: true
497
+ http.access.file_handler:
498
+ enabled: true
499
+ h_type: FILE
500
+ sink: "http/{app_name}.http-access.log"
501
+ http.err.file_handler:
502
+ enabled: true
503
+ h_type: FILE
504
+ sink: "http/{app_name}.http-err.log"
505
+ error: true
506
+ http.access.json_handler:
507
+ enabled: true
508
+ h_type: FILE
509
+ sink: "http.json/{app_name}.http-access.json.log"
510
+ http.err.json_handler:
415
511
  enabled: true
512
+ h_type: FILE
513
+ sink: "http.json/{app_name}.http-err.json.log"
514
+ error: true
416
515
  extra:
417
- http_std_debug_format: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
418
- 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'
419
- http_file_enabled: true
420
- http_file_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}'
421
- http_file_tz: "localtime"
422
- http_log_path: "http/{app_name}.http.access.log"
423
- http_err_path: "http/{app_name}.http.err.log"
424
- http_json_enabled: true
425
- http_json_path: "http.json/{app_name}.http.json.access.log"
426
- http_json_err_path: "http.json/{app_name}.http.json.err.log"
427
516
  ```
428
517
 
429
518
  ### 🌎 Environment Variables
@@ -475,7 +564,7 @@ To build the documentation, run the following command:
475
564
  pip install -r ./requirements/requirements.docs.txt
476
565
 
477
566
  # Serve documentation locally (for development):
478
- mkdocs serve -a 0.0.0.0:8000
567
+ mkdocs serve -a 0.0.0.0:8000 --livereload
479
568
  # Or use the docs script:
480
569
  ./scripts/docs.sh
481
570