|
1 | 1 | import asyncio |
2 | 2 | import logging |
| 3 | +import sys |
3 | 4 | from contextlib import asynccontextmanager |
4 | 5 |
|
5 | 6 | from fastapi import FastAPI |
6 | 7 | from fastapi.middleware.cors import CORSMiddleware |
| 8 | +from loguru import logger |
7 | 9 |
|
8 | 10 | from app import __version__ |
9 | 11 | from app.api.routes import job |
|
12 | 14 | from app.schemas.health import HealthOut |
13 | 15 | from app.wrappers.discord_bot import bot |
14 | 16 |
|
15 | | -logging.basicConfig(level=logging.INFO) |
16 | 17 | settings = get_settings() |
17 | 18 |
|
| 19 | +log_level = 'INFO' |
| 20 | +if settings.DEBUG: |
| 21 | + log_level = 'DEBUG' |
| 22 | + |
| 23 | + |
| 24 | +class InterceptHandler(logging.Handler): |
| 25 | + def emit(self, record: logging.LogRecord): |
| 26 | + # Descobre o nível equivalente no loguru |
| 27 | + try: |
| 28 | + level = logger.level(record.levelname).name |
| 29 | + except ValueError: |
| 30 | + level = record.levelno |
| 31 | + |
| 32 | + # Sobe na call stack para achar o chamador real |
| 33 | + frame, depth = sys._getframe(6), 6 |
| 34 | + while frame and frame.f_code.co_filename == logging.__file__: |
| 35 | + frame = frame.f_back |
| 36 | + depth += 1 |
| 37 | + |
| 38 | + logger.opt(depth=depth, exception=record.exc_info).log( |
| 39 | + level, record.getMessage() |
| 40 | + ) |
| 41 | + |
| 42 | + |
18 | 43 | description = f""" |
19 | 44 | Esta API fornece acesso a vagas de emprego para desenvolvedores, coletadas de diversas fontes. |
20 | 45 |
|
|
28 | 53 | async def lifespan(app: FastAPI): |
29 | 54 | # Startup |
30 | 55 |
|
| 56 | + # Remove o handler padrão do loguru |
| 57 | + logger.remove() |
| 58 | + |
| 59 | + logger.add( |
| 60 | + sys.stdout, |
| 61 | + level=log_level, |
| 62 | + colorize=True, |
| 63 | + ) |
| 64 | + |
| 65 | + # Opcional: salvar em arquivo com rotação |
| 66 | + logger.add( |
| 67 | + 'logs/app.log', |
| 68 | + level=log_level, |
| 69 | + rotation='10 MB', |
| 70 | + retention='7 days', |
| 71 | + compression='zip', |
| 72 | + ) |
| 73 | + |
| 74 | + # Intercepta todos os loggers do Python (uvicorn, sqlalchemy, etc.) |
| 75 | + logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True) |
| 76 | + for name in logging.root.manager.loggerDict: |
| 77 | + logging.getLogger(name).handlers = [InterceptHandler()] |
| 78 | + logging.getLogger(name).propagate = False |
| 79 | + |
31 | 80 | # Aplica migrations pendentes automaticamente no startup |
32 | 81 | proc = await asyncio.create_subprocess_exec( |
33 | 82 | 'alembic', |
|
0 commit comments