Skip to content

Commit 983d383

Browse files
authored
chore: Setup smart logger (#38)
1 parent c70cd0d commit 983d383

File tree

15 files changed

+328
-538
lines changed

15 files changed

+328
-538
lines changed

app/bot/bot.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
from pybotx import Bot
44
from pybotx_fsm import FSMMiddleware
5-
from pybotx_smart_logger import BotXSmartLoggerMiddleware
65

76
from app.bot.commands import common
87
from app.bot.commands.tasks import create_task, delete_task, get_tasks
98
from app.bot.error_handlers.internal_error import internal_error_handler
9+
from app.bot.middlewares.smart_logger import smart_logger_middleware
1010
from app.settings import settings
1111

1212

@@ -21,9 +21,9 @@ def get_bot() -> Bot:
2121
bot_accounts=settings.BOT_CREDENTIALS,
2222
exception_handlers={Exception: internal_error_handler},
2323
middlewares=[
24+
smart_logger_middleware,
2425
FSMMiddleware(
2526
[create_task.fsm, get_tasks.fsm], state_repo_key="redis_repo"
2627
),
27-
BotXSmartLoggerMiddleware(debug_enabled_for_message=True).dispatch,
2828
],
2929
)

app/bot/middlewares/smart_logger.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Middlewares to log all requests using smart logger wrapper."""
2+
3+
from pybotx import Bot, IncomingMessage, IncomingMessageHandlerFunc
4+
from pybotx_smart_logger.wrapper import wrap_smart_logger
5+
6+
from app.services.log_formatters import format_raw_command
7+
from app.settings import settings
8+
9+
10+
async def smart_logger_middleware(
11+
message: IncomingMessage, bot: Bot, call_next: IncomingMessageHandlerFunc
12+
) -> None:
13+
async with wrap_smart_logger(
14+
log_source="Incoming message",
15+
context_func=lambda: format_raw_command(message.raw_command),
16+
debug=settings.DEBUG,
17+
):
18+
await call_next(message, bot)

app/services/log_formatters.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Helpers to format log messages in smart logger wrapper."""
2+
3+
from pprint import pformat
4+
from typing import Any, Dict, Optional
5+
6+
from pybotx.logger import trim_file_data_in_incoming_json
7+
8+
from app.logger import logger
9+
10+
11+
def format_raw_command(raw_command: Optional[Dict[str, Any]]) -> str:
12+
if raw_command is None:
13+
logger.warning("Empty `raw_command`")
14+
return "<empty `raw_command`>"
15+
16+
trimmed_raw_command = trim_file_data_in_incoming_json(raw_command)
17+
return pformat(trimmed_raw_command)

app/settings.py

+29-29
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,43 @@
44
from uuid import UUID
55

66
from pybotx import BotAccountWithSecret
7-
from pydantic import BaseSettings, validator
7+
from pydantic import BaseSettings
88

99

1010
class AppSettings(BaseSettings):
1111
class Config: # noqa: WPS431
1212
env_file = ".env"
1313

14+
@classmethod
15+
def parse_env_var(cls, field_name: str, raw_val: str) -> Any:
16+
if field_name == "BOT_CREDENTIALS":
17+
if not raw_val:
18+
return []
19+
20+
return [
21+
cls._build_credentials_from_string(credentials_str)
22+
for credentials_str in raw_val.replace(",", " ").split()
23+
]
24+
25+
return cls.json_loads(raw_val) # type: ignore
26+
27+
@classmethod
28+
def _build_credentials_from_string(
29+
cls, credentials_str: str
30+
) -> BotAccountWithSecret:
31+
credentials_str = credentials_str.replace("|", "@")
32+
assert credentials_str.count("@") == 2, "Have you forgot to add `bot_id`?"
33+
34+
host, secret_key, bot_id = [
35+
str_value.strip() for str_value in credentials_str.split("@")
36+
]
37+
return BotAccountWithSecret(
38+
id=UUID(bot_id), host=host, secret_key=secret_key
39+
)
40+
1441
# TODO: Change type to `list[BotAccountWithSecret]` after closing:
1542
# https://github.com/samuelcolvin/pydantic/issues/1458
16-
BOT_CREDENTIALS: Any
43+
BOT_CREDENTIALS: List[BotAccountWithSecret]
1744

1845
# base kwargs
1946
DEBUG: bool = False
@@ -25,32 +52,5 @@ class Config: # noqa: WPS431
2552
# redis
2653
REDIS_DSN: str
2754

28-
@validator("BOT_CREDENTIALS", pre=True)
29-
@classmethod
30-
def parse_bot_credentials(cls, raw_credentials: Any) -> List[BotAccountWithSecret]:
31-
"""Parse bot credentials separated by comma.
32-
33-
Each entry must be separated by "@" or "|".
34-
"""
35-
if not raw_credentials:
36-
raise ValueError("`BOT_CREDENTIALS` can't be empty")
37-
38-
return [
39-
cls._build_credentials_from_string(credentials_str)
40-
for credentials_str in raw_credentials.replace(",", " ").split()
41-
]
42-
43-
@classmethod
44-
def _build_credentials_from_string(
45-
cls, credentials_str: str
46-
) -> BotAccountWithSecret:
47-
credentials_str = credentials_str.replace("|", "@")
48-
assert credentials_str.count("@") == 2, "Have you forgot to add `bot_id`?"
49-
50-
host, secret_key, bot_id = [
51-
str_value.strip() for str_value in credentials_str.split("@")
52-
]
53-
return BotAccountWithSecret(id=UUID(bot_id), host=host, secret_key=secret_key)
54-
5555

5656
settings = AppSettings()

poetry.lock

+28-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ authors = []
1111
python = ">=3.8,<3.10"
1212

1313
pybotx-smart-logger = "~0.10.1"
14-
pybotx = "~0.55.2"
14+
pybotx = "0.55.2"
1515
pybotx-fsm = "~0.4.2"
1616

1717
fastapi = "0.95.2"
@@ -24,7 +24,7 @@ pydantic = { version = "~1.10.5", extras = ["dotenv"] }
2424

2525
alembic = "~1.7.6"
2626
SQLAlchemy = "~1.4.31"
27-
asyncpg = "~0.25.0" # DB backend for application
27+
asyncpg = "0.26.0" # DB backend for application
2828
psycopg2-binary = "~2.9.2" # DB backend for alembic (migration tool)
2929
importlib-resources = { version = "^5.4.0", python = "<3.9" }
3030
zipp = { version = "^3.7.0", python = "<3.9" }

0 commit comments

Comments
 (0)