beans-logging-fastapi 1.1.0__tar.gz → 2.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.
- beans_logging_fastapi-2.0.0/.python-version +1 -0
- beans_logging_fastapi-1.1.0/LICENCE.txt → beans_logging_fastapi-2.0.0/LICENSE.txt +1 -1
- beans_logging_fastapi-2.0.0/PKG-INFO +497 -0
- beans_logging_fastapi-2.0.0/README.md +438 -0
- beans_logging_fastapi-2.0.0/pyproject.toml +63 -0
- beans_logging_fastapi-2.0.0/requirements/requirements.build.txt +4 -0
- beans_logging_fastapi-2.0.0/requirements/requirements.dev.txt +6 -0
- beans_logging_fastapi-2.0.0/requirements/requirements.docs.txt +5 -0
- beans_logging_fastapi-2.0.0/requirements/requirements.test.txt +5 -0
- beans_logging_fastapi-2.0.0/requirements.txt +2 -0
- beans_logging_fastapi-2.0.0/setup.py +3 -0
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi/__init__.py +1 -1
- beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/__version__.py +1 -0
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi/_async_log.py +38 -26
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi/_base.py +25 -18
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi/_filters.py +9 -4
- beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_formats.py +95 -0
- beans_logging_fastapi-2.0.0/src/beans_logging_fastapi/_handlers.py +96 -0
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi/_middlewares.py +41 -29
- beans_logging_fastapi-2.0.0/src/beans_logging_fastapi.egg-info/PKG-INFO +497 -0
- beans_logging_fastapi-2.0.0/src/beans_logging_fastapi.egg-info/SOURCES.txt +29 -0
- beans_logging_fastapi-2.0.0/src/beans_logging_fastapi.egg-info/requires.txt +38 -0
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi.egg-info/top_level.txt +1 -1
- beans_logging_fastapi-1.1.0/PKG-INFO +0 -385
- beans_logging_fastapi-1.1.0/README.md +0 -361
- beans_logging_fastapi-1.1.0/beans_logging_fastapi/__version__.py +0 -3
- beans_logging_fastapi-1.1.0/beans_logging_fastapi/_formats.py +0 -77
- beans_logging_fastapi-1.1.0/beans_logging_fastapi/_handlers.py +0 -82
- beans_logging_fastapi-1.1.0/beans_logging_fastapi.egg-info/PKG-INFO +0 -385
- beans_logging_fastapi-1.1.0/beans_logging_fastapi.egg-info/SOURCES.txt +0 -20
- beans_logging_fastapi-1.1.0/beans_logging_fastapi.egg-info/requires.txt +0 -2
- beans_logging_fastapi-1.1.0/setup.py +0 -55
- beans_logging_fastapi-1.1.0/tests/__init__.py +0 -1
- beans_logging_fastapi-1.1.0/tests/conftest.py +0 -16
- beans_logging_fastapi-1.1.0/tests/test_beans_logging_fastapi.py +0 -24
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0}/setup.cfg +0 -0
- {beans_logging_fastapi-1.1.0 → beans_logging_fastapi-2.0.0/src}/beans_logging_fastapi.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.10
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: beans_logging_fastapi
|
|
3
|
+
Version: 2.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<8.0.0,>=7.1.0
|
|
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
|
+
Dynamic: license-file
|
|
59
|
+
|
|
60
|
+
# FastAPI Logging (beans-logging-fastapi)
|
|
61
|
+
|
|
62
|
+
[](https://choosealicense.com/licenses/mit)
|
|
63
|
+
[](https://github.com/bybatkhuu/module-fastapi-logging/actions/workflows/2.build-publish.yml)
|
|
64
|
+
[](https://github.com/bybatkhuu/module-fastapi-logging/releases)
|
|
65
|
+
|
|
66
|
+
This is a middleware for FastAPI HTTP access logs. It is based on **'beans-logging'** package.
|
|
67
|
+
|
|
68
|
+
## ✨ Features
|
|
69
|
+
|
|
70
|
+
- **Logger** based on **'beans-logging'** package
|
|
71
|
+
- **FastAPI** HTTP access logging **middleware**
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🛠 Installation
|
|
76
|
+
|
|
77
|
+
### 1. 🚧 Prerequisites
|
|
78
|
+
|
|
79
|
+
- Install **Python (>= v3.10)** and **pip (>= 23)**:
|
|
80
|
+
- **[RECOMMENDED] [Miniconda (v3)](https://www.anaconda.com/docs/getting-started/miniconda/install)**
|
|
81
|
+
- *[arm64/aarch64] [Miniforge (v3)](https://github.com/conda-forge/miniforge)*
|
|
82
|
+
- *[Python virutal environment] [venv](https://docs.python.org/3/library/venv.html)*
|
|
83
|
+
|
|
84
|
+
[OPTIONAL] For **DEVELOPMENT** environment:
|
|
85
|
+
|
|
86
|
+
- Install [**git**](https://git-scm.com/downloads)
|
|
87
|
+
- Setup an [**SSH key**](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh)
|
|
88
|
+
|
|
89
|
+
### 2. 📦 Install the package
|
|
90
|
+
|
|
91
|
+
[NOTE] Choose one of the following methods to install the package **[A ~ F]**:
|
|
92
|
+
|
|
93
|
+
**OPTION A.** [**RECOMMENDED**] Install from **PyPi**:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
pip install -U beans-logging-fastapi
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**OPTION B.** Install latest version directly from **GitHub** repository:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
pip install git+https://github.com/bybatkhuu/module-fastapi-logging.git
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**OPTION C.** Install from the downloaded **source code**:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
git clone https://github.com/bybatkhuu/module-fastapi-logging.git && \
|
|
109
|
+
cd ./module-fastapi-logging
|
|
110
|
+
|
|
111
|
+
# Install directly from the source code:
|
|
112
|
+
pip install .
|
|
113
|
+
|
|
114
|
+
# Or install with editable mode:
|
|
115
|
+
pip install -e .
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**OPTION D.** Install for **DEVELOPMENT** environment:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
pip install -e .[dev]
|
|
122
|
+
|
|
123
|
+
# Install pre-commit hooks:
|
|
124
|
+
pre-commit install
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**OPTION E.** Install from **pre-built release** files:
|
|
128
|
+
|
|
129
|
+
1. Download **`.whl`** or **`.tar.gz`** file from [**releases**](https://github.com/bybatkhuu/module-fastapi-logging/releases)
|
|
130
|
+
2. Install with pip:
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
# Install from .whl file:
|
|
134
|
+
pip install ./beans_logging_fastapi-[VERSION]-py3-none-any.whl
|
|
135
|
+
|
|
136
|
+
# Or install from .tar.gz file:
|
|
137
|
+
pip install ./beans_logging_fastapi-[VERSION].tar.gz
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**OPTION F.** Copy the **module** into the project directory (for **testing**):
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
# Install python dependencies:
|
|
144
|
+
pip install -r ./requirements.txt
|
|
145
|
+
|
|
146
|
+
# Copy the module source code into the project:
|
|
147
|
+
cp -r ./src/beans_logging_fastapi [PROJECT_DIR]
|
|
148
|
+
# For example:
|
|
149
|
+
cp -r ./src/beans_logging_fastapi /some/path/project/
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## 🚸 Usage/Examples
|
|
153
|
+
|
|
154
|
+
To use `beans_logging_fastapi`:
|
|
155
|
+
|
|
156
|
+
### **FastAPI**
|
|
157
|
+
|
|
158
|
+
[**`configs/logger.yml`**](./examples/configs/logger.yml):
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
logger:
|
|
162
|
+
app_name: "fastapi-app"
|
|
163
|
+
intercept:
|
|
164
|
+
mute_modules: ["uvicorn.access"]
|
|
165
|
+
handlers:
|
|
166
|
+
default.all.file_handler:
|
|
167
|
+
enabled: true
|
|
168
|
+
default.err.file_handler:
|
|
169
|
+
enabled: true
|
|
170
|
+
default.all.json_handler:
|
|
171
|
+
enabled: true
|
|
172
|
+
default.err.json_handler:
|
|
173
|
+
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"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
[**`.env`**](./examples/.env):
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
ENV=development
|
|
191
|
+
DEBUG=true
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
[**`logger.py`**](./examples/logger.py):
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
from typing import TYPE_CHECKING
|
|
198
|
+
|
|
199
|
+
if TYPE_CHECKING:
|
|
200
|
+
from loguru import Record
|
|
201
|
+
|
|
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
|
+
)
|
|
208
|
+
|
|
209
|
+
logger_loader = LoggerLoader()
|
|
210
|
+
logger: Logger = logger_loader.load()
|
|
211
|
+
|
|
212
|
+
|
|
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
|
+
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
|
+
|
|
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
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
__all__ = [
|
|
239
|
+
"logger",
|
|
240
|
+
"logger_loader",
|
|
241
|
+
]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
[**`main.py`**](./examples/main.py):
|
|
245
|
+
|
|
246
|
+
```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__
|
|
267
|
+
|
|
268
|
+
|
|
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
|
+
|
|
279
|
+
|
|
280
|
+
app = FastAPI(lifespan=lifespan, version=__version__)
|
|
281
|
+
|
|
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
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@app.get("/")
|
|
294
|
+
def root():
|
|
295
|
+
return {"Hello": "World"}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@app.get("/items/{item_id}")
|
|
299
|
+
def read_item(item_id: int, q: Union[str, None] = None):
|
|
300
|
+
return {"item_id": item_id, "q": q}
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@app.get("/continue", status_code=100)
|
|
304
|
+
def get_continue():
|
|
305
|
+
return {}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
@app.get("/redirect")
|
|
309
|
+
def redirect():
|
|
310
|
+
return RedirectResponse("/")
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
@app.get("/error")
|
|
314
|
+
def error():
|
|
315
|
+
raise HTTPException(status_code=500)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if __name__ == "__main__":
|
|
319
|
+
uvicorn.run(
|
|
320
|
+
app="main:app",
|
|
321
|
+
host="0.0.0.0",
|
|
322
|
+
port=8000,
|
|
323
|
+
access_log=False,
|
|
324
|
+
server_header=False,
|
|
325
|
+
proxy_headers=True,
|
|
326
|
+
forwarded_allow_ips="*",
|
|
327
|
+
)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Run the [**`examples`**](./examples):
|
|
331
|
+
|
|
332
|
+
```sh
|
|
333
|
+
cd ./examples
|
|
334
|
+
# Install python dependencies for examples:
|
|
335
|
+
pip install -r ./requirements.txt
|
|
336
|
+
|
|
337
|
+
uvicorn main:app --host=0.0.0.0 --port=8000
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Output**:
|
|
341
|
+
|
|
342
|
+
```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]
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
👍
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## ⚙️ Configuration
|
|
366
|
+
|
|
367
|
+
[**`templates/configs/config.yml`**](./templates/configs/config.yml):
|
|
368
|
+
|
|
369
|
+
```yaml
|
|
370
|
+
logger:
|
|
371
|
+
# app_name: "app"
|
|
372
|
+
default:
|
|
373
|
+
level:
|
|
374
|
+
base: INFO
|
|
375
|
+
err: WARNING
|
|
376
|
+
format_str: "[{time:YYYY-MM-DD HH:mm:ss.SSS Z} | {extra[level_short]:<5} | {name}:{line}]: {message}"
|
|
377
|
+
file:
|
|
378
|
+
logs_dir: "./logs"
|
|
379
|
+
rotate_size: 10000000
|
|
380
|
+
rotate_time: "00:00:00"
|
|
381
|
+
retention: 90
|
|
382
|
+
encoding: utf8
|
|
383
|
+
custom_serialize: false
|
|
384
|
+
intercept:
|
|
385
|
+
enabled: true
|
|
386
|
+
only_base: false
|
|
387
|
+
ignore_modules: []
|
|
388
|
+
include_modules: []
|
|
389
|
+
mute_modules: ["uvicorn.access"]
|
|
390
|
+
handlers:
|
|
391
|
+
default.all.std_handler:
|
|
392
|
+
type: STD
|
|
393
|
+
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
|
+
colorize: true
|
|
395
|
+
enabled: true
|
|
396
|
+
default.all.file_handler:
|
|
397
|
+
type: FILE
|
|
398
|
+
sink: "{app_name}.all.log"
|
|
399
|
+
enabled: true
|
|
400
|
+
default.err.file_handler:
|
|
401
|
+
type: FILE
|
|
402
|
+
sink: "{app_name}.err.log"
|
|
403
|
+
error: true
|
|
404
|
+
enabled: true
|
|
405
|
+
default.all.json_handler:
|
|
406
|
+
type: FILE
|
|
407
|
+
sink: "json/{app_name}.json.all.log"
|
|
408
|
+
serialize: true
|
|
409
|
+
enabled: true
|
|
410
|
+
default.err.json_handler:
|
|
411
|
+
type: FILE
|
|
412
|
+
sink: "json/{app_name}.json.err.log"
|
|
413
|
+
serialize: true
|
|
414
|
+
error: true
|
|
415
|
+
enabled: true
|
|
416
|
+
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
|
+
```
|
|
428
|
+
|
|
429
|
+
### 🌎 Environment Variables
|
|
430
|
+
|
|
431
|
+
[**`.env.example`**](./.env.example):
|
|
432
|
+
|
|
433
|
+
```sh
|
|
434
|
+
# ENV=LOCAL
|
|
435
|
+
# DEBUG=false
|
|
436
|
+
# TZ=UTC
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 🧪 Running Tests
|
|
442
|
+
|
|
443
|
+
To run tests, run the following command:
|
|
444
|
+
|
|
445
|
+
```sh
|
|
446
|
+
# Install python test dependencies:
|
|
447
|
+
pip install .[test]
|
|
448
|
+
|
|
449
|
+
# Run tests:
|
|
450
|
+
python -m pytest -sv -o log_cli=true
|
|
451
|
+
# Or use the test script:
|
|
452
|
+
./scripts/test.sh -l -v -c
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## 🏗️ Build Package
|
|
456
|
+
|
|
457
|
+
To build the python package, run the following command:
|
|
458
|
+
|
|
459
|
+
```sh
|
|
460
|
+
# Install python build dependencies:
|
|
461
|
+
pip install -r ./requirements/requirements.build.txt
|
|
462
|
+
|
|
463
|
+
# Build python package:
|
|
464
|
+
python -m build
|
|
465
|
+
# Or use the build script:
|
|
466
|
+
./scripts/build.sh
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## 📝 Generate Docs
|
|
470
|
+
|
|
471
|
+
To build the documentation, run the following command:
|
|
472
|
+
|
|
473
|
+
```sh
|
|
474
|
+
# Install python documentation dependencies:
|
|
475
|
+
pip install -r ./requirements/requirements.docs.txt
|
|
476
|
+
|
|
477
|
+
# Serve documentation locally (for development):
|
|
478
|
+
mkdocs serve -a 0.0.0.0:8000
|
|
479
|
+
# Or use the docs script:
|
|
480
|
+
./scripts/docs.sh
|
|
481
|
+
|
|
482
|
+
# Or build documentation:
|
|
483
|
+
mkdocs build
|
|
484
|
+
# Or use the docs script:
|
|
485
|
+
./scripts/docs.sh -b
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## 📚 Documentation
|
|
489
|
+
|
|
490
|
+
- [Docs](./docs)
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## 📑 References
|
|
495
|
+
|
|
496
|
+
- <https://packaging.python.org/en/latest/tutorials/packaging-projects>
|
|
497
|
+
- <https://python-packaging.readthedocs.io/en/latest>
|