This is a HTTP access log module for FastAPI based on 'beans-logging' package.
Project description
FastAPI Logging (beans-logging-fastapi)
This is a HTTP access log module for FastAPI based on 'beans-logging' package.
✨ Features
- Logger based on 'beans-logging' package
- FastAPI HTTP access logging middleware
- HTTP access log as structured JSON format
- Predefined configuration for HTTP access logs
- Easy to install and use
🛠 Installation
1. 🚧 Prerequisites
- Install Python (>= v3.10) and pip (>= 23):
- [RECOMMENDED] Miniconda (v3)
- [arm64/aarch64] Miniforge (v3)
- [Python virutal environment] venv
[OPTIONAL] For DEVELOPMENT environment:
2. 📦 Install the package
[NOTE] Choose one of the following methods to install the package [A ~ F]:
OPTION A. [RECOMMENDED] Install from PyPi:
pip install -U beans-logging-fastapi
OPTION B. Install latest version directly from GitHub repository:
pip install git+https://github.com/bybatkhuu/module-fastapi-logging.git
OPTION C. Install from the downloaded source code:
git clone https://github.com/bybatkhuu/module-fastapi-logging.git && \
cd ./module-fastapi-logging
# Install directly from the source code:
pip install .
# Or install with editable mode:
pip install -e .
OPTION D. Install for DEVELOPMENT environment:
pip install -e .[dev]
# Install pre-commit hooks:
pre-commit install
OPTION E. Install from pre-built release files:
- Download
.whlor.tar.gzfile from releases - Install with pip:
# Install from .whl file:
pip install ./beans_logging_fastapi-[VERSION]-py3-none-any.whl
# Or install from .tar.gz file:
pip install ./beans_logging_fastapi-[VERSION].tar.gz
OPTION F. Copy the module into the project directory (for testing):
# Install python dependencies:
pip install -r ./requirements.txt
# Copy the module source code into the project:
cp -r ./src/beans_logging_fastapi [PROJECT_DIR]
# For example:
cp -r ./src/beans_logging_fastapi /some/path/project/
🚸 Usage/Examples
To use beans_logging_fastapi:
FastAPI
logger:
app_name: "fastapi-app"
default:
level:
base: TRACE
http:
std:
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'
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>'
debug_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
file:
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}'
tz: "localtime"
headers:
has_proxy: false
has_cf: false
intercept:
mute_modules: ["uvicorn.access"]
handlers:
http.access.file_handler:
enabled: true
sink: "http/{app_name}.http-access.log"
http.err.file_handler:
enabled: true
sink: "http/{app_name}.http-err.log"
http.access.json_handler:
enabled: true
sink: "http.json/{app_name}.http-access.json.log"
http.err.json_handler:
enabled: true
sink: "http.json/{app_name}.http-err.json.log"
.env:
ENV=development
DEBUG=true
import os
from pydantic_settings import BaseSettings
from potato_util import io as io_utils
from beans_logging_fastapi import LoggerConfigPM
_config_path = os.path.join(os.getcwd(), "configs", "logger.yml")
_config_data = {}
if os.path.isfile(_config_path):
_config_data = io_utils.read_config_file(config_path=_config_path)
class MainConfig(BaseSettings):
logger: LoggerConfigPM = LoggerConfigPM()
config = MainConfig(**_config_data)
__all__ = [
"MainConfig",
"config",
]
from beans_logging_fastapi import logger
__all__ = [
"logger",
]
from pydantic import validate_call
from fastapi import FastAPI, APIRouter, HTTPException
from fastapi.responses import RedirectResponse
router = APIRouter()
@router.get("/")
def root():
return {"Hello": "World"}
@router.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
@router.get("/continue", status_code=100)
def get_continue():
return {}
@router.get("/redirect")
def redirect():
return RedirectResponse("/")
@router.get("/error")
def error():
raise HTTPException(status_code=500)
@validate_call(config={"arbitrary_types_allowed": True})
def add_routers(app: FastAPI) -> None:
"""Add routers to FastAPI app.
Args:
app (FastAPI): FastAPI app instance.
"""
app.include_router(router)
return
__all__ = ["add_routers"]
# Standard libraries
from typing import Any
from collections.abc import Callable
# Third-party libraries
import uvicorn
from uvicorn._types import ASGIApplication
from pydantic import validate_call
from fastapi import FastAPI
from beans_logging_fastapi import add_logger
# Internal modules
from __version__ import __version__
from config import config
from lifespan import lifespan
from router import add_routers
def create_app() -> FastAPI:
"""Create FastAPI application instance.
Returns:
FastAPI: FastAPI application instance.
"""
app = FastAPI(lifespan=lifespan, version=__version__)
# Add logger before any other components:
add_logger(app=app, config=config.logger)
# Add any other components after logger:
add_routers(app=app)
return app
@validate_call(config={"arbitrary_types_allowed": True})
def run_server(
app: FastAPI | ASGIApplication | Callable[..., Any] | str = "main:app",
) -> None:
"""Run uvicorn server.
Args:
app (Union[ASGIApplication, str], optional): ASGI application instance or module path.
"""
uvicorn.run(
app=app,
host="0.0.0.0", # nosec B104
port=8000,
access_log=False, # Disable default uvicorn access log
server_header=False,
proxy_headers=False,
forwarded_allow_ips="*",
)
return
__all__ = [
"create_app",
"run_server",
]
#!/usr/bin/env python
# Third-party libraries
from dotenv import load_dotenv
load_dotenv(override=True)
# Internal modules
from bootstrap import create_app, run_server # noqa: E402
from logger import logger # noqa: E402
app = create_app()
def main() -> None:
"""Main function."""
run_server(app=app)
return
if __name__ == "__main__":
logger.info("Starting server from 'main.py'...")
main()
__all__ = ["app"]
Run the examples:
cd ./examples
# Install python dependencies for examples:
pip install -r ./requirements.txt
uvicorn main:app --host=0.0.0.0 --port=8000
Output:
[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'];
[2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.server:84]: Started server process [88375]
[2026-01-01 12:00:00.003 +09:00 | INFO | uvicorn.lifespan.on:48]: Waiting for application startup.
[2026-01-01 12:00:00.004 +09:00 | TRACE | lifespan:19]: TRACE diagnosis is ON!
[2026-01-01 12:00:00.004 +09:00 | DEBUG | lifespan:20]: DEBUG mode is ON!
[2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:21]: Preparing to startup...
[2026-01-01 12:00:00.004 +09:00 | OK | lifespan:24]: Finished preparation to startup.
[2026-01-01 12:00:00.004 +09:00 | INFO | lifespan:25]: Version: 0.0.0
[2026-01-01 12:00:00.005 +09:00 | INFO | uvicorn.lifespan.on:62]: Application startup complete.
[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)
[2026-01-01 12:00:01.775 +09:00 | DEBUG ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1"
[2026-01-01 12:00:01.783 +09:00 | OK ]: [80138308bc00406387fb804cf6cc0e11] 127.0.0.1 - "GET / HTTP/1.1" 200 17B 5.7ms
^C[2026-01-01 12:00:02.368 +09:00 | INFO | uvicorn.server:264]: Shutting down
[2026-01-01 12:00:02.470 +09:00 | INFO | uvicorn.lifespan.on:67]: Waiting for application shutdown.
[2026-01-01 12:00:02.472 +09:00 | INFO | lifespan:29]: Preparing to shutdown...
[2026-01-01 12:00:02.472 +09:00 | OK | lifespan:31]: Finished preparation to shutdown.
[2026-01-01 12:00:02.473 +09:00 | INFO | uvicorn.lifespan.on:76]: Application shutdown complete.
[2026-01-01 12:00:02.474 +09:00 | INFO | uvicorn.server:94]: Finished server process [88375]
👍
⚙️ Configuration
logger:
# app_name: fastapi-app
default:
level:
base: INFO
err: WARNING
format_str: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {extra[level_short]:<5} | {name}:{line}]: {message}"
file:
logs_dir: "./logs"
rotate_size: 10000000
rotate_time: "00:00:00"
retention: 90
encoding: utf8
use_custom_serialize: false
http:
std:
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'
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>'
debug_msg_format_str: '<n>[{request_id}]</n> {client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
file:
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}'
tz: localtime
headers:
has_proxy: false
has_cf: false
intercept:
enabled: true
only_base: false
ignore_modules: []
include_modules: []
mute_modules: [uvicorn.access]
handlers:
all_std_handler:
enabled: true
h_type: STD
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>"
colorize: true
all_file_handler:
enabled: true
h_type: FILE
sink: "{app_name}.all.log"
err_file_handler:
enabled: true
h_type: FILE
sink: "{app_name}.err.log"
error: true
all_json_handler:
enabled: true
h_type: FILE
sink: "json/{app_name}.all.json.log"
serialize: true
err_json_handler:
enabled: true
h_type: FILE
sink: "json/{app_name}.err.json.log"
serialize: true
error: true
http_access_std_handler:
enabled: true
h_type: STD
format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> ]: <level>{message}</level>"
colorize: true
http_access_file_handler:
enabled: true
h_type: FILE
sink: "http/{app_name}.http-access.log"
http_err_file_handler:
enabled: true
h_type: FILE
sink: "http/{app_name}.http-err.log"
error: true
http_access_json_handler:
enabled: true
h_type: FILE
sink: "http.json/{app_name}.http-access.json.log"
http_err_json_handler:
enabled: true
h_type: FILE
sink: "http.json/{app_name}.http-err.json.log"
error: true
extra:
🌎 Environment Variables
# ENV=LOCAL
# DEBUG=false
# TZ=UTC
🧪 Running Tests
To run tests, run the following command:
# Install python test dependencies:
pip install .[test]
# Run tests:
python -m pytest -sv -o log_cli=true
# Or use the test script:
./scripts/test.sh -l -v -c
🏗️ Build Package
To build the python package, run the following command:
# Install python build dependencies:
pip install -r ./requirements/requirements.build.txt
# Build python package:
python -m build
# Or use the build script:
./scripts/build.sh
📝 Generate Docs
To build the documentation, run the following command:
# Install python documentation dependencies:
pip install -r ./requirements/requirements.docs.txt
# Serve documentation locally (for development):
mkdocs serve -a 0.0.0.0:8000 --livereload
# Or use the docs script:
./scripts/docs.sh
# Or build documentation:
mkdocs build
# Or use the docs script:
./scripts/docs.sh -b
📚 Documentation
📑 References
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file beans_logging_fastapi-4.0.1.tar.gz.
File metadata
- Download URL: beans_logging_fastapi-4.0.1.tar.gz
- Upload date:
- Size: 19.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d38be72db16c17f8c433db3760634f385f55f4493cfff8ab64da51c9c9ed1d5
|
|
| MD5 |
5df9a1901296c5f33f7c3c1994e4d46f
|
|
| BLAKE2b-256 |
ec6cd568229ea63598adf8f7119f21b0edba0b3753168924146bb1fdbe9b9781
|
File details
Details for the file beans_logging_fastapi-4.0.1-py3-none-any.whl.
File metadata
- Download URL: beans_logging_fastapi-4.0.1-py3-none-any.whl
- Upload date:
- Size: 16.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e227d837e40aff842db97485d659d0549c7e8edfb61c485b25294d2d71a0246
|
|
| MD5 |
9b5ecd7d069d044f5ed2135bd8dbb61e
|
|
| BLAKE2b-256 |
5290824d053ed48952f28764233f85c270755b2c5ba1a889f3c6d0d9e8e0165c
|