beans-logging-fastapi 1.1.1__py3-none-any.whl → 3.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/__init__.py +6 -24
- beans_logging_fastapi/__version__.py +1 -3
- beans_logging_fastapi/{_async_log.py → _async.py} +39 -27
- beans_logging_fastapi/_core.py +90 -0
- beans_logging_fastapi/config.py +168 -0
- beans_logging_fastapi/constants.py +12 -0
- beans_logging_fastapi/{_filters.py → filters.py} +9 -4
- beans_logging_fastapi/formats.py +95 -0
- beans_logging_fastapi/{_middlewares.py → middlewares.py} +137 -30
- beans_logging_fastapi-3.0.0.dist-info/METADATA +586 -0
- beans_logging_fastapi-3.0.0.dist-info/RECORD +14 -0
- {beans_logging_fastapi-1.1.1.dist-info → beans_logging_fastapi-3.0.0.dist-info}/WHEEL +1 -1
- beans_logging_fastapi-1.1.1.dist-info/LICENCE.txt → beans_logging_fastapi-3.0.0.dist-info/licenses/LICENSE.txt +1 -1
- {beans_logging_fastapi-1.1.1.dist-info → beans_logging_fastapi-3.0.0.dist-info}/top_level.txt +0 -1
- beans_logging_fastapi/_base.py +0 -100
- beans_logging_fastapi/_formats.py +0 -77
- beans_logging_fastapi/_handlers.py +0 -82
- beans_logging_fastapi-1.1.1.dist-info/METADATA +0 -385
- beans_logging_fastapi-1.1.1.dist-info/RECORD +0 -16
- tests/__init__.py +0 -1
- tests/conftest.py +0 -16
- tests/test_beans_logging_fastapi.py +0 -24
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
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.
|
|
5
|
+
Author-email: Batkhuu Byambajav <batkhuu10@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/bybatkhuu/module-fastapi-logging
|
|
7
|
+
Project-URL: Documentation, https://fastapi-logging-docs.bybatkhuu.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/bybatkhuu/module-fastapi-logging.git
|
|
9
|
+
Project-URL: Issues, https://github.com/bybatkhuu/module-fastapi-logging/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/bybatkhuu/module-fastapi-logging/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: beans_logging_fastapi,fastapi-logging,fastapi-logging-middleware,fastapi-middleware,logging-middleware,middleware,beans-logging,http-access-logging,logging,logger,loguru
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Requires-Python: <4.0,>=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE.txt
|
|
24
|
+
Requires-Dist: fastapi<1.0.0,>=0.99.1
|
|
25
|
+
Requires-Dist: beans-logging<9.0.0,>=8.0.2
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-xdist<4.0.0,>=3.6.1; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-benchmark<6.0.0,>=5.0.1; extra == "test"
|
|
31
|
+
Provides-Extra: build
|
|
32
|
+
Requires-Dist: setuptools<81.0.0,>=70.3.0; extra == "build"
|
|
33
|
+
Requires-Dist: wheel<1.0.0,>=0.43.0; extra == "build"
|
|
34
|
+
Requires-Dist: build<2.0.0,>=1.1.1; extra == "build"
|
|
35
|
+
Requires-Dist: twine<7.0.0,>=6.0.1; extra == "build"
|
|
36
|
+
Provides-Extra: docs
|
|
37
|
+
Requires-Dist: pylint<5.0.0,>=3.0.4; extra == "docs"
|
|
38
|
+
Requires-Dist: mkdocs-material<10.0.0,>=9.5.50; extra == "docs"
|
|
39
|
+
Requires-Dist: mkdocs-awesome-nav<4.0.0,>=3.0.0; extra == "docs"
|
|
40
|
+
Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "docs"
|
|
41
|
+
Requires-Dist: mike<3.0.0,>=2.1.3; extra == "docs"
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: pytest<10.0.0,>=8.0.2; extra == "dev"
|
|
44
|
+
Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-xdist<4.0.0,>=3.6.1; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest-benchmark<6.0.0,>=5.0.1; extra == "dev"
|
|
47
|
+
Requires-Dist: setuptools<81.0.0,>=70.3.0; extra == "dev"
|
|
48
|
+
Requires-Dist: wheel<1.0.0,>=0.43.0; extra == "dev"
|
|
49
|
+
Requires-Dist: build<2.0.0,>=1.1.1; extra == "dev"
|
|
50
|
+
Requires-Dist: twine<7.0.0,>=6.0.1; extra == "dev"
|
|
51
|
+
Requires-Dist: pylint<5.0.0,>=3.0.4; extra == "dev"
|
|
52
|
+
Requires-Dist: mkdocs-material<10.0.0,>=9.5.50; extra == "dev"
|
|
53
|
+
Requires-Dist: mkdocs-awesome-nav<4.0.0,>=3.0.0; extra == "dev"
|
|
54
|
+
Requires-Dist: mkdocstrings[python]<2.0.0,>=0.24.3; extra == "dev"
|
|
55
|
+
Requires-Dist: mike<3.0.0,>=2.1.3; extra == "dev"
|
|
56
|
+
Requires-Dist: pyright<2.0.0,>=1.1.392; extra == "dev"
|
|
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"
|
|
59
|
+
Dynamic: license-file
|
|
60
|
+
|
|
61
|
+
# FastAPI Logging (beans-logging-fastapi)
|
|
62
|
+
|
|
63
|
+
[](https://choosealicense.com/licenses/mit)
|
|
64
|
+
[](https://github.com/bybatkhuu/module-fastapi-logging/actions/workflows/2.build-publish.yml)
|
|
65
|
+
[](https://github.com/bybatkhuu/module-fastapi-logging/releases)
|
|
66
|
+
|
|
67
|
+
This is a HTTP access logging module for **FastAPI** based on **'beans-logging'** package.
|
|
68
|
+
|
|
69
|
+
## ✨ Features
|
|
70
|
+
|
|
71
|
+
- **Logger** based on **'beans-logging'** package
|
|
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**
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 🛠 Installation
|
|
80
|
+
|
|
81
|
+
### 1. 🚧 Prerequisites
|
|
82
|
+
|
|
83
|
+
- Install **Python (>= v3.10)** and **pip (>= 23)**:
|
|
84
|
+
- **[RECOMMENDED] [Miniconda (v3)](https://www.anaconda.com/docs/getting-started/miniconda/install)**
|
|
85
|
+
- *[arm64/aarch64] [Miniforge (v3)](https://github.com/conda-forge/miniforge)*
|
|
86
|
+
- *[Python virutal environment] [venv](https://docs.python.org/3/library/venv.html)*
|
|
87
|
+
|
|
88
|
+
[OPTIONAL] For **DEVELOPMENT** environment:
|
|
89
|
+
|
|
90
|
+
- Install [**git**](https://git-scm.com/downloads)
|
|
91
|
+
- Setup an [**SSH key**](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh)
|
|
92
|
+
|
|
93
|
+
### 2. 📦 Install the package
|
|
94
|
+
|
|
95
|
+
[NOTE] Choose one of the following methods to install the package **[A ~ F]**:
|
|
96
|
+
|
|
97
|
+
**OPTION A.** [**RECOMMENDED**] Install from **PyPi**:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
pip install -U beans-logging-fastapi
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**OPTION B.** Install latest version directly from **GitHub** repository:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
pip install git+https://github.com/bybatkhuu/module-fastapi-logging.git
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**OPTION C.** Install from the downloaded **source code**:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
git clone https://github.com/bybatkhuu/module-fastapi-logging.git && \
|
|
113
|
+
cd ./module-fastapi-logging
|
|
114
|
+
|
|
115
|
+
# Install directly from the source code:
|
|
116
|
+
pip install .
|
|
117
|
+
|
|
118
|
+
# Or install with editable mode:
|
|
119
|
+
pip install -e .
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**OPTION D.** Install for **DEVELOPMENT** environment:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
pip install -e .[dev]
|
|
126
|
+
|
|
127
|
+
# Install pre-commit hooks:
|
|
128
|
+
pre-commit install
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**OPTION E.** Install from **pre-built release** files:
|
|
132
|
+
|
|
133
|
+
1. Download **`.whl`** or **`.tar.gz`** file from [**releases**](https://github.com/bybatkhuu/module-fastapi-logging/releases)
|
|
134
|
+
2. Install with pip:
|
|
135
|
+
|
|
136
|
+
```sh
|
|
137
|
+
# Install from .whl file:
|
|
138
|
+
pip install ./beans_logging_fastapi-[VERSION]-py3-none-any.whl
|
|
139
|
+
|
|
140
|
+
# Or install from .tar.gz file:
|
|
141
|
+
pip install ./beans_logging_fastapi-[VERSION].tar.gz
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**OPTION F.** Copy the **module** into the project directory (for **testing**):
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
# Install python dependencies:
|
|
148
|
+
pip install -r ./requirements.txt
|
|
149
|
+
|
|
150
|
+
# Copy the module source code into the project:
|
|
151
|
+
cp -r ./src/beans_logging_fastapi [PROJECT_DIR]
|
|
152
|
+
# For example:
|
|
153
|
+
cp -r ./src/beans_logging_fastapi /some/path/project/
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 🚸 Usage/Examples
|
|
157
|
+
|
|
158
|
+
To use `beans_logging_fastapi`:
|
|
159
|
+
|
|
160
|
+
### **FastAPI**
|
|
161
|
+
|
|
162
|
+
[**`configs/logger.yml`**](./examples/configs/logger.yml):
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
logger:
|
|
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
|
|
181
|
+
intercept:
|
|
182
|
+
mute_modules: ["uvicorn.access"]
|
|
183
|
+
handlers:
|
|
184
|
+
http.access.file_handler:
|
|
185
|
+
enabled: true
|
|
186
|
+
sink: "http/{app_name}.http-access.log"
|
|
187
|
+
http.err.file_handler:
|
|
188
|
+
enabled: true
|
|
189
|
+
sink: "http/{app_name}.http-err.log"
|
|
190
|
+
http.access.json_handler:
|
|
191
|
+
enabled: true
|
|
192
|
+
sink: "http.json/{app_name}.http-access.json.log"
|
|
193
|
+
http.err.json_handler:
|
|
194
|
+
enabled: true
|
|
195
|
+
sink: "http.json/{app_name}.http-err.json.log"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
[**`.env`**](./examples/.env):
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
ENV=development
|
|
202
|
+
DEBUG=true
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
[**`config.py`**](./examples/config.py):
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
import os
|
|
209
|
+
|
|
210
|
+
from pydantic_settings import BaseSettings
|
|
211
|
+
|
|
212
|
+
from potato_util import io as io_utils
|
|
213
|
+
from beans_logging_fastapi import LoggerConfigPM
|
|
214
|
+
|
|
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)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class MainConfig(BaseSettings):
|
|
223
|
+
logger: LoggerConfigPM = LoggerConfigPM()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
config = MainConfig(**_config_data)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
__all__ = [
|
|
230
|
+
"MainConfig",
|
|
231
|
+
"config",
|
|
232
|
+
]
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
[**`logger.py`**](./examples/logger.py):
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
from beans_logging_fastapi import logger
|
|
239
|
+
|
|
240
|
+
__all__ = [
|
|
241
|
+
"logger",
|
|
242
|
+
]
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
[**`router.py`**](./examples/router.py):
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from pydantic import validate_call
|
|
249
|
+
from fastapi import FastAPI, APIRouter, HTTPException
|
|
250
|
+
from fastapi.responses import RedirectResponse
|
|
251
|
+
|
|
252
|
+
router = APIRouter()
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@router.get("/")
|
|
256
|
+
def root():
|
|
257
|
+
return {"Hello": "World"}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
@router.get("/items/{item_id}")
|
|
261
|
+
def read_item(item_id: int, q: str | None = None):
|
|
262
|
+
return {"item_id": item_id, "q": q}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@router.get("/continue", status_code=100)
|
|
266
|
+
def get_continue():
|
|
267
|
+
return {}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@router.get("/redirect")
|
|
271
|
+
def redirect():
|
|
272
|
+
return RedirectResponse("/")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@router.get("/error")
|
|
276
|
+
def error():
|
|
277
|
+
raise HTTPException(status_code=500)
|
|
278
|
+
|
|
279
|
+
|
|
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
|
+
|
|
346
|
+
uvicorn.run(
|
|
347
|
+
app=app,
|
|
348
|
+
host="0.0.0.0", # nosec B104
|
|
349
|
+
port=8000,
|
|
350
|
+
access_log=False, # Disable default uvicorn access log
|
|
351
|
+
server_header=False,
|
|
352
|
+
proxy_headers=False,
|
|
353
|
+
forwarded_allow_ips="*",
|
|
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"]
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Run the [**`examples`**](./examples):
|
|
399
|
+
|
|
400
|
+
```sh
|
|
401
|
+
cd ./examples
|
|
402
|
+
# Install python dependencies for examples:
|
|
403
|
+
pip install -r ./requirements.txt
|
|
404
|
+
|
|
405
|
+
uvicorn main:app --host=0.0.0.0 --port=8000
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Output**:
|
|
409
|
+
|
|
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]
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
👍
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## ⚙️ Configuration
|
|
436
|
+
|
|
437
|
+
[**`templates/configs/config.yml`**](./templates/configs/config.yml):
|
|
438
|
+
|
|
439
|
+
```yaml
|
|
440
|
+
logger:
|
|
441
|
+
# app_name: fastapi-app
|
|
442
|
+
default:
|
|
443
|
+
level:
|
|
444
|
+
base: INFO
|
|
445
|
+
err: WARNING
|
|
446
|
+
format_str: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {extra[level_short]:<5} | {name}:{line}]: {message}"
|
|
447
|
+
file:
|
|
448
|
+
logs_dir: "./logs"
|
|
449
|
+
rotate_size: 10000000
|
|
450
|
+
rotate_time: "00:00:00"
|
|
451
|
+
retention: 90
|
|
452
|
+
encoding: utf8
|
|
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
|
|
465
|
+
intercept:
|
|
466
|
+
enabled: true
|
|
467
|
+
only_base: false
|
|
468
|
+
ignore_modules: []
|
|
469
|
+
include_modules: []
|
|
470
|
+
mute_modules: [uvicorn.access]
|
|
471
|
+
handlers:
|
|
472
|
+
default.all.std_handler:
|
|
473
|
+
enabled: true
|
|
474
|
+
h_type: STD
|
|
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
|
+
colorize: true
|
|
477
|
+
default.all.file_handler:
|
|
478
|
+
enabled: true
|
|
479
|
+
h_type: FILE
|
|
480
|
+
sink: "{app_name}.all.log"
|
|
481
|
+
default.err.file_handler:
|
|
482
|
+
enabled: true
|
|
483
|
+
h_type: FILE
|
|
484
|
+
sink: "{app_name}.err.log"
|
|
485
|
+
error: true
|
|
486
|
+
default.all.json_handler:
|
|
487
|
+
enabled: true
|
|
488
|
+
h_type: FILE
|
|
489
|
+
sink: "json/{app_name}.all.json.log"
|
|
490
|
+
serialize: true
|
|
491
|
+
default.err.json_handler:
|
|
492
|
+
enabled: true
|
|
493
|
+
h_type: FILE
|
|
494
|
+
sink: "json/{app_name}.err.json.log"
|
|
495
|
+
serialize: true
|
|
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:
|
|
511
|
+
enabled: true
|
|
512
|
+
h_type: FILE
|
|
513
|
+
sink: "http.json/{app_name}.http-err.json.log"
|
|
514
|
+
error: true
|
|
515
|
+
extra:
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### 🌎 Environment Variables
|
|
519
|
+
|
|
520
|
+
[**`.env.example`**](./.env.example):
|
|
521
|
+
|
|
522
|
+
```sh
|
|
523
|
+
# ENV=LOCAL
|
|
524
|
+
# DEBUG=false
|
|
525
|
+
# TZ=UTC
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## 🧪 Running Tests
|
|
531
|
+
|
|
532
|
+
To run tests, run the following command:
|
|
533
|
+
|
|
534
|
+
```sh
|
|
535
|
+
# Install python test dependencies:
|
|
536
|
+
pip install .[test]
|
|
537
|
+
|
|
538
|
+
# Run tests:
|
|
539
|
+
python -m pytest -sv -o log_cli=true
|
|
540
|
+
# Or use the test script:
|
|
541
|
+
./scripts/test.sh -l -v -c
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## 🏗️ Build Package
|
|
545
|
+
|
|
546
|
+
To build the python package, run the following command:
|
|
547
|
+
|
|
548
|
+
```sh
|
|
549
|
+
# Install python build dependencies:
|
|
550
|
+
pip install -r ./requirements/requirements.build.txt
|
|
551
|
+
|
|
552
|
+
# Build python package:
|
|
553
|
+
python -m build
|
|
554
|
+
# Or use the build script:
|
|
555
|
+
./scripts/build.sh
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
## 📝 Generate Docs
|
|
559
|
+
|
|
560
|
+
To build the documentation, run the following command:
|
|
561
|
+
|
|
562
|
+
```sh
|
|
563
|
+
# Install python documentation dependencies:
|
|
564
|
+
pip install -r ./requirements/requirements.docs.txt
|
|
565
|
+
|
|
566
|
+
# Serve documentation locally (for development):
|
|
567
|
+
mkdocs serve -a 0.0.0.0:8000 --livereload
|
|
568
|
+
# Or use the docs script:
|
|
569
|
+
./scripts/docs.sh
|
|
570
|
+
|
|
571
|
+
# Or build documentation:
|
|
572
|
+
mkdocs build
|
|
573
|
+
# Or use the docs script:
|
|
574
|
+
./scripts/docs.sh -b
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
## 📚 Documentation
|
|
578
|
+
|
|
579
|
+
- [Docs](./docs)
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## 📑 References
|
|
584
|
+
|
|
585
|
+
- <https://packaging.python.org/en/latest/tutorials/packaging-projects>
|
|
586
|
+
- <https://python-packaging.readthedocs.io/en/latest>
|
|
@@ -0,0 +1,14 @@
|
|
|
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,,
|