Skip to main content

FastAPI Logging (beans-logging-fastapi)

MIT License GitHub Workflow Status GitHub release (latest SemVer) PyPI PyPI - Python Version

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

[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:

  1. Download .whl or .tar.gz file from releases
  2. 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

configs/logger.yml:

logger:
  app_name: "fastapi-app"
  level:
    base: TRACE
  http:
    has_proxy_headers: false
    has_cf_headers: false
  intercept:
    mute_modules: ["uvicorn.access"]
  handlers:
    std_handler:
      enabled: true
    http_access_std_handler:
      enabled: true
    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

config.py:

import os

from pydantic_settings import BaseSettings

from potato_util import io as io_utils
from beans_logging_fastapi import LoggerConfigPM


_config_data = {}
_configs_dir = os.path.join(os.getcwd(), "configs")
if os.path.isdir(_configs_dir):
    _config_data = io_utils.read_all_configs(configs_dir=_configs_dir)


class MainConfig(BaseSettings):
    logger: LoggerConfigPM = LoggerConfigPM()


config = MainConfig(**_config_data)


__all__ = [
    "MainConfig",
    "config",
]

logger.py:

from beans_logging_fastapi import logger

__all__ = [
    "logger",
]

router.py:

from pydantic import validate_call
from fastapi import FastAPI, APIRouter, HTTPException, Request
from fastapi.responses import RedirectResponse

router = APIRouter()


@router.get("/")
def root(request: Request):
    _logger = request.state.logger
    _logger.info("Root endpoint accessed.")

    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"]

bootstrap.py:

# 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",
]

main.py:

#!/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-06-05 00:55:29.335 +09:00 | TRACE | - | beans_logging.intercepters:96]: Intercepted modules: ['potato_util', 'dotenv.main', 'concurrent', 'potato_util.io', 'asyncio', 'fastapi', 'concurrent.futures', 'dotenv', 'uvicorn', 'watchfiles.watcher', 'potato_util.io._sync', 'watchfiles.main', 'potato_util._base', 'uvicorn.error', 'watchfiles']; Muted modules: ['uvicorn.access'];
[2026-06-05 00:55:29.336 +09:00 | INFO  | - | uvicorn.server:84]: Started server process [95017]
[2026-06-05 00:55:29.336 +09:00 | INFO  | - | uvicorn.lifespan.on:48]: Waiting for application startup.
[2026-06-05 00:55:29.337 +09:00 | TRACE | - | lifespan:19]: TRACE diagnosis is ON!
[2026-06-05 00:55:29.337 +09:00 | DEBUG | - | lifespan:20]: DEBUG mode is ON!
[2026-06-05 00:55:29.337 +09:00 | INFO  | - | lifespan:21]: Preparing to startup...
[2026-06-05 00:55:29.337 +09:00 | OK    | - | lifespan:24]: Finished preparation to startup.
[2026-06-05 00:55:29.337 +09:00 | INFO  | - | lifespan:25]: Version: 0.0.0
[2026-06-05 00:55:29.337 +09:00 | INFO  | - | uvicorn.lifespan.on:62]: Application startup complete.
[2026-06-05 00:55:29.339 +09:00 | INFO  | - | uvicorn.server:216]: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
[2026-06-05 00:55:33.367 +09:00 | DEBUG | 58c916d045844314bb6c10b390ad5593]: 127.0.0.1 - "GET / HTTP/1.1"
[2026-06-05 00:55:33.370 +09:00 | INFO  | 58c916d045844314bb6c10b390ad5593 | router:11]: Root endpoint accessed.
[2026-06-05 00:55:33.371 +09:00 | OK    | 58c916d045844314bb6c10b390ad5593]: 127.0.0.1 - "GET / HTTP/1.1" 200 17B 3.0ms
^C[2026-06-05 00:55:35.702 +09:00 | INFO  | - | uvicorn.server:264]: Shutting down
[2026-06-05 00:55:35.805 +09:00 | INFO  | - | uvicorn.lifespan.on:67]: Waiting for application shutdown.
[2026-06-05 00:55:35.805 +09:00 | INFO  | - | lifespan:29]: Preparing to shutdown...
[2026-06-05 00:55:35.805 +09:00 | OK    | - | lifespan:31]: Finished preparation to shutdown.
[2026-06-05 00:55:35.805 +09:00 | INFO  | - | uvicorn.lifespan.on:76]: Application shutdown complete.
[2026-06-05 00:55:35.806 +09:00 | INFO  | - | uvicorn.server:94]: Finished server process [95017]

👍


⚙️ Configuration

templates/configs/config.yml:

logger:
  # app_name: fastapi-app
  level:
    base: INFO
    err: WARNING
  default_format: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {extra[level_short]:<5} | {name}:{line} {extra[request_id]}]: {message}"
  file:
    logs_dir: "./logs"
    rotate_size: 10000000
    rotate_time: "00:00:00"
    retention: 90
    encoding: utf8
  custom_serialize: false
  http:
    std:
      sub_format: '{client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" {status_code} {content_length}B {response_time}ms'
      err_sub_format: '{client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}" <n>{status_code}</n>'
      debug_sub_format: '{client_host} {user_id} "<u>{method} {url_path}</u> HTTP/{http_version}"'
    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}'
      tz: localtime
    has_proxy_headers: true
    has_cf_headers: true
  intercept:
    enabled: true
    only_base: false
    ignore_modules: []
    include_modules: []
    mute_modules: [uvicorn.access]
  global_extra:
    trace_id: ""
    request_id: ""
    user_id: ""
  handlers:
    std_handler:
      enabled: true
      type_: STD
      format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> | <w>{name}:{line}</w> <d><w>{extra[request_id]}</w></d>]: <level>{message}</level>"
      colorize: true
    file_handler:
      enabled: true
      type_: FILE
      sink: "{app_name}.all.log"
    err_file_handler:
      enabled: true
      type_: FILE
      sink: "{app_name}.err.log"
      error: true
    json_handler:
      enabled: true
      type_: FILE
      sink: "json/{app_name}.all.json.log"
      serialize: true
    err_json_handler:
      enabled: true
      type_: FILE
      sink: "json/{app_name}.err.json.log"
      serialize: true
      error: true
    http_access_std_handler:
      enabled: true
      type_: STD
      format: "[<c>{time:YYYY-MM-DD HH:mm:ss.SSS Z}</c> | <level>{extra[level_short]:<5}</level> | <d><w>{extra[request_id]}</w></d>]: <level>{message}</level>"
      colorize: true
    http_access_file_handler:
      enabled: true
      type_: FILE
      sink: "http/{app_name}.http-access.log"
    http_err_file_handler:
      enabled: true
      type_: FILE
      sink: "http/{app_name}.http-err.log"
      error: true
    http_access_json_handler:
      enabled: true
      type_: FILE
      sink: "http.json/{app_name}.http-access.json.log"
    http_err_json_handler:
      enabled: true
      type_: FILE
      sink: "http.json/{app_name}.http-err.json.log"
      error: true
  extra:

🌎 Environment Variables

.env.example:

# 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

Metadata

Release files for beans-logging-fastapi 8.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for beans-logging-fastapi 8.2.3
File Size Uploaded
beans_logging_fastapi-8.2.3.tar.gz 20.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for beans-logging-fastapi 8.2.3
File Interpreter ABI Platform
beans_logging_fastapi-8.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 39.5 kB

Release files / beans_logging_fastapi-8.2.3.tar.gz

Download URL beans_logging_fastapi-8.2.3.tar.gz
Size 20.9 kB
Tags Source
SHA-256 checksum
How to use checksums
016bdd8020d88776e22fc96b102bbf4c2beaef1be213aba234dfece0329074d9
BLAKE2b-256 checksum
How to use checksums
10ed0bf0f2d3fe35e030ce085e204c6496c789765182406c203d89625c746a5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Release files / beans_logging_fastapi-8.2.3-py3-none-any.whl

Download URL beans_logging_fastapi-8.2.3-py3-none-any.whl
Size 18.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
152ae486a342367ae5e8c0e02496423c0cc3b9d5f867a4907121398059ab5039
BLAKE2b-256 checksum
How to use checksums
5ad3f07205321730283e217cca1f5d93524f2db982227887c5ea7bb6ee40bc8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.16

Release history Release notifications | RSS feed

This release

8.2.3 This release

2 release files

8.2.2

2 release files

8.2.1

2 release files

8.2.0

2 release files

8.1.2

2 release files

8.1.1

2 release files

8.1.0

2 release files

8.0.3

2 release files

8.0.2

2 release files

8.0.1

2 release files

8.0.0

2 release files

7.0.0

2 release files

6.0.4

2 release files

6.0.3

2 release files

6.0.2

2 release files

6.0.1

2 release files

6.0.0

2 release files

5.2.2

2 release files

5.2.1

2 release files

5.2.0

2 release files

5.1.2

2 release files

5.1.1

2 release files

5.1.0

2 release files

5.0.0

2 release files

4.1.1

2 release files

4.1.0

2 release files

4.0.1

2 release files

4.0.0

2 release files

3.0.0

2 release files

2.0.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page