Skip to content

Commit 60ccafb

Browse files
Feature/improve logger (#9)
* add logger utils to reformat default logger with ECS logger; * add ecs-logging and update libs; * replace all default loguru with ecs logger; * disable uvicorn default logger; * allow controlling alembic and sqlalchemy logs through env;
1 parent 588475b commit 60ccafb

File tree

24 files changed

+517
-214
lines changed

24 files changed

+517
-214
lines changed

alembic.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,17 @@ keys = console
8989
keys = generic
9090

9191
[logger_root]
92-
level = WARN
92+
level = ERROR
9393
handlers = console
9494
qualname =
9595

9696
[logger_sqlalchemy]
97-
level = WARN
97+
level = ERROR
9898
handlers =
9999
qualname = sqlalchemy.engine
100100

101101
[logger_alembic]
102-
level = INFO
102+
level = ERROR
103103
handlers =
104104
qualname = alembic
105105

config.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,48 @@
11
from typing import Optional
22

33
from dynaconf import Dynaconf
4-
from loguru import logger
54
from pydantic import BaseModel, Field
65

6+
7+
# We'll use a deferred logger to avoid circular imports
8+
# This will be replaced with the actual logger once it's available
9+
class DeferredLogger:
10+
def __init__(self):
11+
self.messages = []
12+
self.real_logger = None
13+
14+
def _log(self, level, message, *args, **kwargs):
15+
if self.real_logger:
16+
getattr(self.real_logger, level)(message, *args, **kwargs)
17+
else:
18+
self.messages.append((level, message, args, kwargs))
19+
20+
def info(self, message, *args, **kwargs):
21+
self._log("info", message, *args, **kwargs)
22+
23+
def warning(self, message, *args, **kwargs):
24+
self._log("warning", message, *args, **kwargs)
25+
26+
def error(self, message, *args, **kwargs):
27+
self._log("error", message, *args, **kwargs)
28+
29+
def exception(self, message, *args, **kwargs):
30+
self._log("exception", message, *args, **kwargs)
31+
32+
def debug(self, message, *args, **kwargs):
33+
self._log("debug", message, *args, **kwargs)
34+
35+
def set_real_logger(self, _logger):
36+
self.real_logger = _logger
37+
# Replay any deferred messages
38+
for level, message, args, kwargs in self.messages:
39+
getattr(self.real_logger, level)(message, *args, **kwargs)
40+
self.messages = []
41+
42+
43+
# Create a deferred logger
44+
logger = DeferredLogger()
45+
746
# Load settings
847
settings = Dynaconf(
948
envvar_prefix="APP",
@@ -35,6 +74,7 @@ class AuthenticationServiceConfig(BaseModel):
3574
class RelationalDBConfig(BaseModel):
3675
vendor: Optional[str] = Field("postgres", alias="VENDOR")
3776
url: str = Field(..., alias="URL")
77+
enable_log: bool = Field(..., alias="ENABLE_LOG")
3878
enable_auto_migrate: bool = Field(..., alias="ENABLE_AUTO_MIGRATE")
3979

4080

@@ -67,6 +107,7 @@ class AppConfig(BaseModel):
67107
RELATIONAL_DB=RelationalDBConfig(
68108
VENDOR=settings.RELATIONAL_DB.VENDOR,
69109
URL=settings.RELATIONAL_DB.URL,
110+
ENABLE_LOG=settings.RELATIONAL_DB.ENABLE_LOG,
70111
ENABLE_AUTO_MIGRATE=settings.RELATIONAL_DB.ENABLE_AUTO_MIGRATE,
71112
),
72113
AUTHENTICATION_SERVICE=AuthenticationServiceConfig(

config/settings.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ MAIN_HTTP_PORT = 8082
33
HEALTH_CHECK_HTTP_PORT = 5000
44
LOG_LEVEL = "INFO"
55
UVICORN_WORKERS = 1
6-
RELATIONAL_DB = '@json { "VENDOR": "postgres", "URL": "postgresql+asyncpg://cleanarc:cleanarc!123@localhost:5432/cleanarc", "ENABLE_AUTO_MIGRATE": true}'
6+
RELATIONAL_DB = '@json { "VENDOR": "postgres", "URL": "postgresql+asyncpg://cleanarc:cleanarc!123@localhost:5432/cleanarc", "ENABLE_LOG": false, "ENABLE_AUTO_MIGRATE": true}'
77
AUTHENTICATION_SERVICE = '@json { "VENDOR": "keycloak", "URL": "http://localhost:8081", "ADMIN_USERNAME": "", "ADMIN_PASSWORD": "", "REALM": "clean-arc", "CLIENT_ID": "python-clean-arc-be", "CLIENT_SECRET": "", "WEBHOOK_SECRET": ""}'
88
REBAC_AUTHORIZATION_SERVICE = '@json { "VENDOR": "openfga", "URL": "http://localhost:8080", "TOKEN": "", "STORE_ID": "", "AUTHORIZATION_MODEL_ID": "", "TIMEOUT_IN_MILLIS": 3000 }'

internal/app/middlewares.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from fastapi.responses import ORJSONResponse
55
from jwcrypto.jws import InvalidJWSObject
66
from jwcrypto.jwt import JWTExpired
7-
from loguru import logger
87
from starlette import status
98
from starlette.middleware.base import BaseHTTPMiddleware
109

@@ -17,6 +16,9 @@
1716
from internal.domains.entities import JWTPayload
1817
from internal.domains.services.abstraction import AbstractAuthenticationSVC
1918
from internal.patterns import Container
19+
from utils.logger_utils import get_shared_logger
20+
21+
logger = get_shared_logger()
2022

2123

2224
class JWTAuthMiddleware(BaseHTTPMiddleware):

internal/app/servers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from fastapi import FastAPI, HTTPException
22
from fastapi.encoders import jsonable_encoder
33
from fastapi.responses import ORJSONResponse
4-
from loguru import logger
54
from starlette.middleware.cors import CORSMiddleware
65
from starlette.requests import Request
76

87
from internal.app import JWTAuthMiddleware
98
from internal.controllers.http.v1.routes import api_router as api_router_v1
109
from internal.controllers.responses import DataResponse, MessageResponse
10+
from utils.logger_utils import get_shared_logger
11+
12+
logger = get_shared_logger()
1113

1214
app_status = {"alive": True, "status_code": 200, "message": "I'm fine"}
1315

internal/controllers/http/v1/endpoints/authentication.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from fastapi import APIRouter, Depends, Request
55
from fastapi.encoders import jsonable_encoder
66
from fastapi.responses import ORJSONResponse
7-
from loguru import logger
87

98
from internal.controllers.responses import DataResponse
109
from internal.controllers.responses.error_code import (
@@ -16,6 +15,9 @@
1615
from internal.domains.errors import UnauthorizedWebhookException
1716
from internal.domains.services import AuthenticationSVC
1817
from internal.patterns import Container
18+
from utils.logger_utils import get_shared_logger
19+
20+
logger = get_shared_logger()
1921

2022
router = APIRouter()
2123

internal/controllers/http/v1/endpoints/comment.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from fastapi import APIRouter, Depends, Request
55
from fastapi.encoders import jsonable_encoder
66
from fastapi.responses import ORJSONResponse
7-
from loguru import logger
87
from pydantic import UUID4, Field, ValidationError
98

109
from internal.controllers.http.payloads import (
@@ -41,6 +40,9 @@
4140
)
4241
from internal.domains.services import CommentSVC
4342
from internal.patterns import Container
43+
from utils.logger_utils import get_shared_logger
44+
45+
logger = get_shared_logger()
4446

4547
router = APIRouter()
4648

internal/controllers/http/v1/endpoints/post.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from fastapi import APIRouter, Depends, Request
55
from fastapi.encoders import jsonable_encoder
66
from fastapi.responses import ORJSONResponse
7-
from loguru import logger
87
from pydantic import UUID4, Field, ValidationError
98

109
from internal.controllers.http.payloads import CreatePostRequestV1, UpdatePostRequestV1
@@ -35,6 +34,9 @@
3534
)
3635
from internal.domains.services import PostSVC
3736
from internal.patterns import Container
37+
from utils.logger_utils import get_shared_logger
38+
39+
logger = get_shared_logger()
3840

3941
router = APIRouter()
4042

internal/domains/services/authentication.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from typing import Optional, Tuple
22

33
from fastapi import Request
4-
from loguru import logger
54

65
from internal.domains.constants import WebhookEventOperation, WebhookEventResource
76
from internal.domains.entities import CreateUserPayload, WebhookEventEntity
@@ -21,8 +20,11 @@
2120
from internal.infrastructures.relational_db.patterns import (
2221
AbstractUnitOfWork as RelationalDBUnitOfWork,
2322
)
23+
from utils.logger_utils import get_shared_logger
2424
from utils.time_utils import DATETIME_DEFAULT_FORMAT, from_dt_to_str
2525

26+
logger = get_shared_logger()
27+
2628

2729
class AuthenticationSVC(AbstractAuthenticationSVC):
2830
def __init__(

internal/domains/services/comment.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from typing import List, Optional, Tuple
22

3-
from loguru import logger
4-
53
from internal.domains.constants import V1ReBACObjectType, V1ReBACRelation
64
from internal.domains.entities import (
75
CommentEntity,
@@ -30,6 +28,9 @@
3028
from internal.infrastructures.relational_db.patterns import (
3129
AbstractUnitOfWork as RelationalDBUnitOfWork,
3230
)
31+
from utils.logger_utils import get_shared_logger
32+
33+
logger = get_shared_logger()
3334

3435

3536
class CommentSVC(AbstractCommentSVC):

0 commit comments

Comments
 (0)