From 441119510055fb7fd7cca502e6a3d3c4e84c4b09 Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 4 Dec 2023 00:54:31 +0400 Subject: [PATCH 01/11] Create basic logging --- src/Logger/FileSystemLoguruLogger.py | 23 +++++++++++++++++++++++ src/Logger/Logger.py | 17 +++++++++++++++++ src/Logger/exceptionHandler.py | 17 +++++++++++++++++ src/definitions.py | 3 +++ src/main.py | 4 ++++ token.txt | 1 + 6 files changed, 65 insertions(+) create mode 100644 src/Logger/FileSystemLoguruLogger.py create mode 100644 src/Logger/Logger.py create mode 100644 src/Logger/exceptionHandler.py create mode 100644 src/definitions.py create mode 100644 token.txt diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py new file mode 100644 index 0000000..11c3d14 --- /dev/null +++ b/src/Logger/FileSystemLoguruLogger.py @@ -0,0 +1,23 @@ +from Logger.Logger import Logger +from definitions import ROOT_DIR +from loguru import logger + + +class FileSystemLoguruLogger(Logger): + + def __init__(self): + self._log_path = ROOT_DIR + "/application.log" + logger.add(self._log_path, rotation="500 MB", format="{time} {level} {message}", backtrace=True, ) + + def log_error(self, error: Exception): + print('exception logged') + logger.error(error) + + def log_warning(self, message): + logger.warning(message) + + def log_info(self, message): + logger.info(message) + + +MainLogger = FileSystemLoguruLogger() diff --git a/src/Logger/Logger.py b/src/Logger/Logger.py new file mode 100644 index 0000000..ea97118 --- /dev/null +++ b/src/Logger/Logger.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod, ABCMeta + + +class Logger: + __metaclass__ = ABCMeta + + @abstractmethod + def log_error(self, error): + """Print error""" + + @abstractmethod + def log_warning(self, message): + """Print Warning""" + + @abstractmethod + def log_info(self, message): + """Print info""" diff --git a/src/Logger/exceptionHandler.py b/src/Logger/exceptionHandler.py new file mode 100644 index 0000000..f1b1f47 --- /dev/null +++ b/src/Logger/exceptionHandler.py @@ -0,0 +1,17 @@ +import sys +import time + +from Logger.FileSystemLoguruLogger import MainLogger + + + +def init_exception_handling(): + def exception_hook(type, value, traceback): + if type == KeyboardInterrupt: + pass + else: + print("exception handled") + MainLogger.log_error(value) + sys.__excepthook__(type, value, traceback) + + sys.excepthook = exception_hook diff --git a/src/definitions.py b/src/definitions.py new file mode 100644 index 0000000..1267de0 --- /dev/null +++ b/src/definitions.py @@ -0,0 +1,3 @@ +import os + +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/main.py b/src/main.py index 3d34578..df14685 100644 --- a/src/main.py +++ b/src/main.py @@ -1,10 +1,14 @@ import os +from Logger.exceptionHandler import init_exception_handling + # Get the environment variable token = os.getenv('TELEGRAM_TOKEN') +init_exception_handling() # Check if the token is available if token: + raise Exception("test", 'testabcd') print("Token:", token) else: print("TELEGRAM_TOKEN not found") diff --git a/token.txt b/token.txt new file mode 100644 index 0000000..fa43a20 --- /dev/null +++ b/token.txt @@ -0,0 +1 @@ +6926057907:AAGrOIUOUn-KpffUf3RGLNCxiv6srAirQLc \ No newline at end of file From 2df6d06186e22e0bf0939fe5fc65da4ce5e5741c Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 8 Jan 2024 15:49:27 +0400 Subject: [PATCH 02/11] Make error handling with annotation --- .gitignore | 4 +++- src/Logger/FileSystemLoguruLogger.py | 15 ++++++++++++--- src/Logger/exceptionHandler.py | 21 ++++++++------------- src/bot/file_receiver.py | 2 +- src/bot/main.py | 7 ++++--- src/definitions.py | 3 --- src/helperModules/definitions.py | 4 +++- 7 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 src/definitions.py diff --git a/.gitignore b/.gitignore index 7c1d86f..76921e1 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ var/ venv* dump* -.env \ No newline at end of file +.env + +.idea \ No newline at end of file diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py index 11c3d14..4522168 100644 --- a/src/Logger/FileSystemLoguruLogger.py +++ b/src/Logger/FileSystemLoguruLogger.py @@ -1,16 +1,18 @@ from Logger.Logger import Logger -from definitions import ROOT_DIR from loguru import logger +import os + +from src.helperModules.definitions import ROOT_DIR, MB class FileSystemLoguruLogger(Logger): + FILE_SYSTEM_LOGGER_FILE_SIZE = 500 * MB def __init__(self): self._log_path = ROOT_DIR + "/application.log" - logger.add(self._log_path, rotation="500 MB", format="{time} {level} {message}", backtrace=True, ) + logger.add(self._log_path, format="{time} {level} {message}", backtrace=True, ) def log_error(self, error: Exception): - print('exception logged') logger.error(error) def log_warning(self, message): @@ -19,5 +21,12 @@ def log_warning(self, message): def log_info(self, message): logger.info(message) + def _rotate_logs(self): + file_size = os.stat(self._log_path) + if file_size > self.FILE_SYSTEM_LOGGER_FILE_SIZE: + self._clear_logs() + def _clear_logs(self): + os.remove(self._log_path) + MainLogger = FileSystemLoguruLogger() diff --git a/src/Logger/exceptionHandler.py b/src/Logger/exceptionHandler.py index f1b1f47..c6ab54a 100644 --- a/src/Logger/exceptionHandler.py +++ b/src/Logger/exceptionHandler.py @@ -1,17 +1,12 @@ -import sys -import time -from Logger.FileSystemLoguruLogger import MainLogger +from src.Logger.FileSystemLoguruLogger import MainLogger +def handle_exceptions(func): + def result(): + try: + func() + except Exception as e: + MainLogger.log_error(e) -def init_exception_handling(): - def exception_hook(type, value, traceback): - if type == KeyboardInterrupt: - pass - else: - print("exception handled") - MainLogger.log_error(value) - sys.__excepthook__(type, value, traceback) - - sys.excepthook = exception_hook + return result diff --git a/src/bot/file_receiver.py b/src/bot/file_receiver.py index 012bb1c..1b536b4 100644 --- a/src/bot/file_receiver.py +++ b/src/bot/file_receiver.py @@ -1,12 +1,12 @@ import logging from aiogram import types +from src.helperModules.definitions import MB # our modules from src.helperModules.message_helper import MessageHelper class FileReceiver: - MB = 1024 * 1024 # Bytes in megabyte DOCUMENT_SIZE_LIMIT = 100 * MB # 100 MB VIDEO_SIZE_LIMIT = 500 * MB # 500 MB diff --git a/src/bot/main.py b/src/bot/main.py index 8e3260b..b40977e 100644 --- a/src/bot/main.py +++ b/src/bot/main.py @@ -5,6 +5,7 @@ # aiogram modules from aiogram import Bot, Dispatcher, types +from src.Logger.exceptionHandler import handle_exceptions # our modules from src.bot.file_receiver import FileReceiver from src.helperModules.definitions import TOKEN @@ -32,10 +33,10 @@ async def start_polling(self) -> None: await self.dp.start_polling(self.bot) +@handle_exceptions async def main() -> None: - bot = TelegramBot(TOKEN) - await bot.start_polling() + bot = TelegramBot(TOKEN) + await bot.start_polling() if __name__ == "__main__": - logging.basicConfig(level=logging.INFO, stream=sys.stdout) asyncio.run(main()) diff --git a/src/definitions.py b/src/definitions.py deleted file mode 100644 index 1267de0..0000000 --- a/src/definitions.py +++ /dev/null @@ -1,3 +0,0 @@ -import os - -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/helperModules/definitions.py b/src/helperModules/definitions.py index 6320efd..59fbd28 100644 --- a/src/helperModules/definitions.py +++ b/src/helperModules/definitions.py @@ -1,5 +1,7 @@ +import os from dotenv import dotenv_values config = dotenv_values('.env') - TOKEN = config.get('TOKEN') +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) +MB = 1024 * 1024 From f0af0a765b934a35a925e8e8198d72f5c4802f07 Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 4 Dec 2023 00:54:31 +0400 Subject: [PATCH 03/11] Create basic logging --- src/Logger/FileSystemLoguruLogger.py | 23 +++++++++++++++++++++++ src/Logger/Logger.py | 17 +++++++++++++++++ src/Logger/exceptionHandler.py | 17 +++++++++++++++++ src/definitions.py | 3 +++ src/main.py | 15 +++++++++++++++ token.txt | 1 + 6 files changed, 76 insertions(+) create mode 100644 src/Logger/FileSystemLoguruLogger.py create mode 100644 src/Logger/Logger.py create mode 100644 src/Logger/exceptionHandler.py create mode 100644 src/definitions.py create mode 100644 src/main.py create mode 100644 token.txt diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py new file mode 100644 index 0000000..11c3d14 --- /dev/null +++ b/src/Logger/FileSystemLoguruLogger.py @@ -0,0 +1,23 @@ +from Logger.Logger import Logger +from definitions import ROOT_DIR +from loguru import logger + + +class FileSystemLoguruLogger(Logger): + + def __init__(self): + self._log_path = ROOT_DIR + "/application.log" + logger.add(self._log_path, rotation="500 MB", format="{time} {level} {message}", backtrace=True, ) + + def log_error(self, error: Exception): + print('exception logged') + logger.error(error) + + def log_warning(self, message): + logger.warning(message) + + def log_info(self, message): + logger.info(message) + + +MainLogger = FileSystemLoguruLogger() diff --git a/src/Logger/Logger.py b/src/Logger/Logger.py new file mode 100644 index 0000000..ea97118 --- /dev/null +++ b/src/Logger/Logger.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod, ABCMeta + + +class Logger: + __metaclass__ = ABCMeta + + @abstractmethod + def log_error(self, error): + """Print error""" + + @abstractmethod + def log_warning(self, message): + """Print Warning""" + + @abstractmethod + def log_info(self, message): + """Print info""" diff --git a/src/Logger/exceptionHandler.py b/src/Logger/exceptionHandler.py new file mode 100644 index 0000000..f1b1f47 --- /dev/null +++ b/src/Logger/exceptionHandler.py @@ -0,0 +1,17 @@ +import sys +import time + +from Logger.FileSystemLoguruLogger import MainLogger + + + +def init_exception_handling(): + def exception_hook(type, value, traceback): + if type == KeyboardInterrupt: + pass + else: + print("exception handled") + MainLogger.log_error(value) + sys.__excepthook__(type, value, traceback) + + sys.excepthook = exception_hook diff --git a/src/definitions.py b/src/definitions.py new file mode 100644 index 0000000..1267de0 --- /dev/null +++ b/src/definitions.py @@ -0,0 +1,3 @@ +import os + +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..df14685 --- /dev/null +++ b/src/main.py @@ -0,0 +1,15 @@ +import os + +from Logger.exceptionHandler import init_exception_handling + +# Get the environment variable +token = os.getenv('TELEGRAM_TOKEN') + +init_exception_handling() +# Check if the token is available +if token: + raise Exception("test", 'testabcd') + print("Token:", token) +else: + print("TELEGRAM_TOKEN not found") + diff --git a/token.txt b/token.txt new file mode 100644 index 0000000..fa43a20 --- /dev/null +++ b/token.txt @@ -0,0 +1 @@ +6926057907:AAGrOIUOUn-KpffUf3RGLNCxiv6srAirQLc \ No newline at end of file From 62e187bd2ec87221b9de5acb82c87490cbcc703a Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 8 Jan 2024 15:49:27 +0400 Subject: [PATCH 04/11] Make error handling with annotation --- .gitignore | 4 +++- src/Logger/FileSystemLoguruLogger.py | 15 ++++++++++++--- src/Logger/exceptionHandler.py | 21 ++++++++------------- src/bot/file_receiver.py | 2 +- src/bot/main.py | 7 ++++--- src/definitions.py | 3 --- src/helperModules/definitions.py | 4 +++- 7 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 src/definitions.py diff --git a/.gitignore b/.gitignore index 7c1d86f..76921e1 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ var/ venv* dump* -.env \ No newline at end of file +.env + +.idea \ No newline at end of file diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py index 11c3d14..4522168 100644 --- a/src/Logger/FileSystemLoguruLogger.py +++ b/src/Logger/FileSystemLoguruLogger.py @@ -1,16 +1,18 @@ from Logger.Logger import Logger -from definitions import ROOT_DIR from loguru import logger +import os + +from src.helperModules.definitions import ROOT_DIR, MB class FileSystemLoguruLogger(Logger): + FILE_SYSTEM_LOGGER_FILE_SIZE = 500 * MB def __init__(self): self._log_path = ROOT_DIR + "/application.log" - logger.add(self._log_path, rotation="500 MB", format="{time} {level} {message}", backtrace=True, ) + logger.add(self._log_path, format="{time} {level} {message}", backtrace=True, ) def log_error(self, error: Exception): - print('exception logged') logger.error(error) def log_warning(self, message): @@ -19,5 +21,12 @@ def log_warning(self, message): def log_info(self, message): logger.info(message) + def _rotate_logs(self): + file_size = os.stat(self._log_path) + if file_size > self.FILE_SYSTEM_LOGGER_FILE_SIZE: + self._clear_logs() + def _clear_logs(self): + os.remove(self._log_path) + MainLogger = FileSystemLoguruLogger() diff --git a/src/Logger/exceptionHandler.py b/src/Logger/exceptionHandler.py index f1b1f47..c6ab54a 100644 --- a/src/Logger/exceptionHandler.py +++ b/src/Logger/exceptionHandler.py @@ -1,17 +1,12 @@ -import sys -import time -from Logger.FileSystemLoguruLogger import MainLogger +from src.Logger.FileSystemLoguruLogger import MainLogger +def handle_exceptions(func): + def result(): + try: + func() + except Exception as e: + MainLogger.log_error(e) -def init_exception_handling(): - def exception_hook(type, value, traceback): - if type == KeyboardInterrupt: - pass - else: - print("exception handled") - MainLogger.log_error(value) - sys.__excepthook__(type, value, traceback) - - sys.excepthook = exception_hook + return result diff --git a/src/bot/file_receiver.py b/src/bot/file_receiver.py index 012bb1c..1b536b4 100644 --- a/src/bot/file_receiver.py +++ b/src/bot/file_receiver.py @@ -1,12 +1,12 @@ import logging from aiogram import types +from src.helperModules.definitions import MB # our modules from src.helperModules.message_helper import MessageHelper class FileReceiver: - MB = 1024 * 1024 # Bytes in megabyte DOCUMENT_SIZE_LIMIT = 100 * MB # 100 MB VIDEO_SIZE_LIMIT = 500 * MB # 500 MB diff --git a/src/bot/main.py b/src/bot/main.py index 8e3260b..b40977e 100644 --- a/src/bot/main.py +++ b/src/bot/main.py @@ -5,6 +5,7 @@ # aiogram modules from aiogram import Bot, Dispatcher, types +from src.Logger.exceptionHandler import handle_exceptions # our modules from src.bot.file_receiver import FileReceiver from src.helperModules.definitions import TOKEN @@ -32,10 +33,10 @@ async def start_polling(self) -> None: await self.dp.start_polling(self.bot) +@handle_exceptions async def main() -> None: - bot = TelegramBot(TOKEN) - await bot.start_polling() + bot = TelegramBot(TOKEN) + await bot.start_polling() if __name__ == "__main__": - logging.basicConfig(level=logging.INFO, stream=sys.stdout) asyncio.run(main()) diff --git a/src/definitions.py b/src/definitions.py deleted file mode 100644 index 1267de0..0000000 --- a/src/definitions.py +++ /dev/null @@ -1,3 +0,0 @@ -import os - -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/src/helperModules/definitions.py b/src/helperModules/definitions.py index 6320efd..59fbd28 100644 --- a/src/helperModules/definitions.py +++ b/src/helperModules/definitions.py @@ -1,5 +1,7 @@ +import os from dotenv import dotenv_values config = dotenv_values('.env') - TOKEN = config.get('TOKEN') +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) +MB = 1024 * 1024 From 3dd671afefc51536bf12a0e708d805d156aa9da4 Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 13:21:33 +0400 Subject: [PATCH 05/11] Working Logger which saves log files in direcotry from the container --- .env_example | 1 + .gitignore | 7 ++++- README.md | 8 +++++- docker-compose.yml | 14 +++++++--- src/Logger/FileSystemLoguruLogger.py | 38 +++++++++++++++++++--------- src/Logger/Logger.py | 19 +++++++++----- src/Logger/__init__.py | 0 src/Logger/exceptionHandler.py | 14 +++++----- src/bot/main.py | 6 ++++- src/helperModules/definitions.py | 5 ++-- src/main.py | 15 ----------- 11 files changed, 78 insertions(+), 49 deletions(-) create mode 100644 src/Logger/__init__.py delete mode 100644 src/main.py diff --git a/.env_example b/.env_example index 051e1aa..3940b68 100644 --- a/.env_example +++ b/.env_example @@ -1,4 +1,5 @@ TOKEN="tgtoken" +LOG_DIR="./logs" POSTGRES_USER=dbuser POSTGRES_PASSWORD=dbpass POSTGRES_DB=dbname diff --git a/.gitignore b/.gitignore index 76921e1..f43c62c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ __pycache__/ *.py[cod] +# Ignore all contents of the logs directory +logs/* + +# But do not ignore the logs directory itself +!logs/ # C extensions *.so @@ -26,4 +31,4 @@ venv* dump* .env -.idea \ No newline at end of file +.idea diff --git a/README.md b/README.md index b444cac..9bc6795 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,16 @@ A Python-based Telegram bot leveraging GCP to organize and share academic resour 1. Create a copy of .env_example and rename it to .env. 2. Fill in all the necessary variables in the .env file. -## Running the Application +## Running the Application without docker compose (no db, no loggin on main machine) To build the Docker image and start the application, run the following commands: ```py docker build -t telegram_bot . docker run -it --name Telegram_bot telegram_bot ``` + +## Running the Application with docker compose +```py +docker-compose down +docker-compose up --build +```

(back to top)

diff --git a/docker-compose.yml b/docker-compose.yml index 24101d3..d37defc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,25 @@ -version: 'X' +version: '3.8' services: bot: build: . + container_name: telegram_bot + volumes: + - ${LOG_DIR}:/usr/src/app/logs # Use LOG_DIR environment variable + environment: + - TOKEN=${TOKEN} + - LOG_DIR=/usr/src/app/logs # Set the LOG_DIR environment variable inside the container + postgres: image: postgres volumes: - - postgres-data:/var/lib/postgresql/data + - postgres-data:/var/lib/postgresql/data ports: - "${POSTGRES_PORTS}" environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} + volumes: - postgres-data: \ No newline at end of file + postgres-data: diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py index 4522168..3083704 100644 --- a/src/Logger/FileSystemLoguruLogger.py +++ b/src/Logger/FileSystemLoguruLogger.py @@ -1,16 +1,26 @@ -from Logger.Logger import Logger from loguru import logger import os - -from src.helperModules.definitions import ROOT_DIR, MB - +import sys +from src.helperModules.definitions import MB +from src.Logger.Logger import Logger class FileSystemLoguruLogger(Logger): FILE_SYSTEM_LOGGER_FILE_SIZE = 500 * MB def __init__(self): - self._log_path = ROOT_DIR + "/application.log" - logger.add(self._log_path, format="{time} {level} {message}", backtrace=True, ) + log_dir = os.getenv('LOG_DIR', '/usr/src/app/logs') + if not os.path.exists(log_dir): + os.makedirs(log_dir) + self._log_path = os.path.join(log_dir, "application.log") + print(f"Log path: {self._log_path}") + logger.remove() + logger.add(sys.stderr, level="DEBUG") + logger.add(self._log_path, + format="{time} {level} {message}", + backtrace=True, + rotation=self._rotate_logs, + retention="10 days") # Keep log files for 10 days + logger.info(f"Logger initialized. Log path: {self._log_path}") def log_error(self, error: Exception): logger.error(error) @@ -21,12 +31,16 @@ def log_warning(self, message): def log_info(self, message): logger.info(message) - def _rotate_logs(self): - file_size = os.stat(self._log_path) - if file_size > self.FILE_SYSTEM_LOGGER_FILE_SIZE: - self._clear_logs() - def _clear_logs(self): - os.remove(self._log_path) + def log_debug(self, message): + logger.debug(message) + + def log_critical(self, message): + logger.critical(message) + def _rotate_logs(self, message, file): + file.seek(0, os.SEEK_END) + if file.tell() > self.FILE_SYSTEM_LOGGER_FILE_SIZE: + return True # Rotate the log file + return False # Don't rotate the log file MainLogger = FileSystemLoguruLogger() diff --git a/src/Logger/Logger.py b/src/Logger/Logger.py index ea97118..a293c20 100644 --- a/src/Logger/Logger.py +++ b/src/Logger/Logger.py @@ -1,17 +1,22 @@ from abc import ABC, abstractmethod, ABCMeta - -class Logger: - __metaclass__ = ABCMeta - +class Logger(metaclass=ABCMeta): @abstractmethod def log_error(self, error): - """Print error""" + """Log an error""" @abstractmethod def log_warning(self, message): - """Print Warning""" + """Log a warning""" @abstractmethod def log_info(self, message): - """Print info""" + """Log an info""" + + @abstractmethod + def log_debug(self, message): + """Log a debug message""" + + @abstractmethod + def log_critical(self, message): + """Log a critical message""" diff --git a/src/Logger/__init__.py b/src/Logger/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/Logger/exceptionHandler.py b/src/Logger/exceptionHandler.py index c6ab54a..89b6887 100644 --- a/src/Logger/exceptionHandler.py +++ b/src/Logger/exceptionHandler.py @@ -1,12 +1,12 @@ - +from functools import wraps from src.Logger.FileSystemLoguruLogger import MainLogger - def handle_exceptions(func): - def result(): + @wraps(func) + def wrapper(*args, **kwargs): try: - func() + return func(*args, **kwargs) except Exception as e: - MainLogger.log_error(e) - - return result + MainLogger.log_error(f"Exception in {func.__name__}: {e}") + raise + return wrapper diff --git a/src/bot/main.py b/src/bot/main.py index b40977e..e8779fe 100644 --- a/src/bot/main.py +++ b/src/bot/main.py @@ -5,7 +5,10 @@ # aiogram modules from aiogram import Bot, Dispatcher, types +# our exception handler from src.Logger.exceptionHandler import handle_exceptions +from src.Logger.FileSystemLoguruLogger import MainLogger + # our modules from src.bot.file_receiver import FileReceiver from src.helperModules.definitions import TOKEN @@ -13,6 +16,7 @@ class TelegramBot: def __init__(self, token: str): + MainLogger.log_info(f"Starting the bot with token: AmigoBot") self.bot = Bot(token) self.dp = Dispatcher() self.file_receiver = FileReceiver() @@ -26,7 +30,7 @@ async def content_handler(self, message: types.Message) -> None: await self.file_receiver.classify_and_handle_message(message) except Exception as e: - logging.error(f"Error occurred: {e}") + MainLogger.log_error(f"Error occurred: {e}") await message.answer("Error processing the message.") async def start_polling(self) -> None: diff --git a/src/helperModules/definitions.py b/src/helperModules/definitions.py index 59fbd28..7b0bef1 100644 --- a/src/helperModules/definitions.py +++ b/src/helperModules/definitions.py @@ -3,5 +3,6 @@ config = dotenv_values('.env') TOKEN = config.get('TOKEN') -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -MB = 1024 * 1024 +LOG_DIR = config.get('LOG_DIR') +ROOT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'bot') +MB = 1024 * 1024 # Define MB as 1,048,576 bytes diff --git a/src/main.py b/src/main.py deleted file mode 100644 index df14685..0000000 --- a/src/main.py +++ /dev/null @@ -1,15 +0,0 @@ -import os - -from Logger.exceptionHandler import init_exception_handling - -# Get the environment variable -token = os.getenv('TELEGRAM_TOKEN') - -init_exception_handling() -# Check if the token is available -if token: - raise Exception("test", 'testabcd') - print("Token:", token) -else: - print("TELEGRAM_TOKEN not found") - From 7b9782ee901029b8d85b0128c91889a9b0aa082b Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 13:38:18 +0400 Subject: [PATCH 06/11] Resolved flake8 problems (have problems with video and file content. The mesaging is not sent) --- src/Logger/FileSystemLoguruLogger.py | 6 ++++-- src/Logger/Logger.py | 2 +- src/bot/main.py | 8 +++----- src/helperModules/definitions.py | 7 +++++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py index 3083704..6be9f93 100644 --- a/src/Logger/FileSystemLoguruLogger.py +++ b/src/Logger/FileSystemLoguruLogger.py @@ -4,6 +4,7 @@ from src.helperModules.definitions import MB from src.Logger.Logger import Logger + class FileSystemLoguruLogger(Logger): FILE_SYSTEM_LOGGER_FILE_SIZE = 500 * MB @@ -15,8 +16,8 @@ def __init__(self): print(f"Log path: {self._log_path}") logger.remove() logger.add(sys.stderr, level="DEBUG") - logger.add(self._log_path, - format="{time} {level} {message}", + logger.add(self._log_path, + format="{time} {level} {message}", backtrace=True, rotation=self._rotate_logs, retention="10 days") # Keep log files for 10 days @@ -43,4 +44,5 @@ def _rotate_logs(self, message, file): return True # Rotate the log file return False # Don't rotate the log file + MainLogger = FileSystemLoguruLogger() diff --git a/src/Logger/Logger.py b/src/Logger/Logger.py index a293c20..2bb3f5c 100644 --- a/src/Logger/Logger.py +++ b/src/Logger/Logger.py @@ -1,4 +1,4 @@ -from abc import ABC, abstractmethod, ABCMeta +from abc import abstractmethod, ABCMeta class Logger(metaclass=ABCMeta): @abstractmethod diff --git a/src/bot/main.py b/src/bot/main.py index e8779fe..ee95021 100644 --- a/src/bot/main.py +++ b/src/bot/main.py @@ -1,6 +1,4 @@ import asyncio -import logging -import sys # aiogram modules from aiogram import Bot, Dispatcher, types @@ -16,7 +14,6 @@ class TelegramBot: def __init__(self, token: str): - MainLogger.log_info(f"Starting the bot with token: AmigoBot") self.bot = Bot(token) self.dp = Dispatcher() self.file_receiver = FileReceiver() @@ -39,8 +36,9 @@ async def start_polling(self) -> None: @handle_exceptions async def main() -> None: - bot = TelegramBot(TOKEN) - await bot.start_polling() + MainLogger.log_info("Starting the bot with token: AmigoBot") + bot = TelegramBot(TOKEN) + await bot.start_polling() if __name__ == "__main__": asyncio.run(main()) diff --git a/src/helperModules/definitions.py b/src/helperModules/definitions.py index 7b0bef1..ab85352 100644 --- a/src/helperModules/definitions.py +++ b/src/helperModules/definitions.py @@ -4,5 +4,8 @@ config = dotenv_values('.env') TOKEN = config.get('TOKEN') LOG_DIR = config.get('LOG_DIR') -ROOT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'bot') -MB = 1024 * 1024 # Define MB as 1,048,576 bytes +ROOT_DIR = os.path.join( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + 'bot' +) +MB = 1024 * 1024 # Define MB as 1,048,576 bytes From fd270bc36d7fb28f22162308ce8a6e8aa23a8b85 Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 13:44:47 +0400 Subject: [PATCH 07/11] Resolved problem with video and file handling --- src/bot/file_receiver.py | 68 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/bot/file_receiver.py b/src/bot/file_receiver.py index 1b536b4..a36ba5c 100644 --- a/src/bot/file_receiver.py +++ b/src/bot/file_receiver.py @@ -4,6 +4,7 @@ from src.helperModules.definitions import MB # our modules from src.helperModules.message_helper import MessageHelper +from src.Logger.FileSystemLoguruLogger import MainLogger class FileReceiver: @@ -13,6 +14,7 @@ class FileReceiver: async def classify_and_handle_message(self, message: types.Message): try: message_type = MessageHelper.determine_message_type(message) + MainLogger.log_info(f"Message type determined: {message_type}") if message_type == "link": await self.handle_link(message) @@ -24,52 +26,53 @@ async def classify_and_handle_message(self, message: types.Message): await self.handle_unknown_content(message) except Exception as e: - logging.error(f"Error occurred: {e}") + MainLogger.log_error(f"Error occurred: {e}") await message.answer("Error processing the message.") async def handle_link(self, message: types.Message): - # TODO Handle link-specific logic + MainLogger.log_info("Handling link") metadata = self.create_metadata(message) - self.print_metadata(metadata) + self.log_metadata(metadata) await message.answer("This is a link") async def handle_document(self, message: types.Message): - # TODO Handle document-specific logic, including size check - if message.document.file_size > self.DOCUMENT_SIZE_LIMIT: - await message.answer("Document size exceeds 100 MB limit.") - return - metadata = self.create_metadata(message) - self.print_metadata(metadata) - # TODO Further processing (e.g., storage) + MainLogger.log_info("Handling document") + try: + if message.document.file_size > self.DOCUMENT_SIZE_LIMIT: + await message.answer("Document size exceeds 100 MB limit.") + return + metadata = self.create_metadata(message) + self.log_metadata(metadata) + await message.answer("Document received") + except Exception as e: + MainLogger.log_error(f"Error handling document: {e}") + await message.answer("Error processing the document.") async def handle_video(self, message: types.Message): - # TODO Handle video-specific logic, including size check - if message.video.file_size > self.VIDEO_SIZE_LIMIT: - await message.answer("Video size exceeds 500 MB limit.") - return - metadata = self.create_metadata(message) - self.print_metadata(metadata) - # TODO Further processing (e.g., storage) + MainLogger.log_info("Handling video") + try: + if message.video.file_size > self.VIDEO_SIZE_LIMIT: + await message.answer("Video size exceeds 500 MB limit.") + return + metadata = self.create_metadata(message) + self.log_metadata(metadata) + await message.answer("Video received") + except Exception as e: + MainLogger.log_error(f"Error handling video: {e}") + await message.answer("Error processing the video.") async def handle_unknown_content(self, message: types.Message): - # TODO Handle unknown content type logic + MainLogger.log_info("Handling unknown content") await message.answer("Unknown content type") def create_metadata(self, message: types.Message): sender = message.from_user sender_id = sender.id if sender else None - if sender and sender.username: - sender_username = f"@{sender.username}" - else: - sender_username = "No username" - - if sender: - sender_name = sender.first_name - if sender.last_name: - sender_name += f" {sender.last_name}" - else: - sender_name = "No name" + sender_username = f"@{sender.username}" if sender and sender.username else "No username" + sender_name = sender.first_name if sender else "No name" + if sender and sender.last_name: + sender_name += f" {sender.last_name}" message_type = MessageHelper.determine_message_type(message) iso_formatted_date = message.date.isoformat() @@ -86,9 +89,9 @@ def create_metadata(self, message: types.Message): return metadata - def print_metadata(self, metadata): + def log_metadata(self, metadata): for key, value in metadata.items(): - print(f"{key}: {value}") + MainLogger.log_info(f"{key}: {value}") def get_file_size(self, message: types.Message): message_type = MessageHelper.determine_message_type(message) @@ -98,5 +101,4 @@ def get_file_size(self, message: types.Message): elif message_type == "video": return message.video.file_size else: - # No file size for other types (like link or text) - return 0 + return 0 # No file size for other types (like link or text) \ No newline at end of file From 84b81498e6737239b6e4f49f0e26f6e7d881f15c Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 13:52:16 +0400 Subject: [PATCH 08/11] making CI/CD work again with new loggings --- .github/workflows/docker-build-test.yml | 2 +- src/bot/main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build-test.yml b/.github/workflows/docker-build-test.yml index c9db618..03d2d6a 100644 --- a/.github/workflows/docker-build-test.yml +++ b/.github/workflows/docker-build-test.yml @@ -26,7 +26,7 @@ jobs: - name: Check Logs for Bot Start run: | - if docker logs telegram_bot | grep -q "INFO:aiogram.dispatcher:Start polling"; then + if docker logs telegram_bot | grep -q "Bot STARTED"; then echo "Bot started successfully" docker stop telegram_bot else diff --git a/src/bot/main.py b/src/bot/main.py index ee95021..c60887b 100644 --- a/src/bot/main.py +++ b/src/bot/main.py @@ -17,6 +17,7 @@ def __init__(self, token: str): self.bot = Bot(token) self.dp = Dispatcher() self.file_receiver = FileReceiver() + MainLogger.log_info("Bot STARTED") # Register the content handler self.dp.message.register(self.content_handler) @@ -36,7 +37,6 @@ async def start_polling(self) -> None: @handle_exceptions async def main() -> None: - MainLogger.log_info("Starting the bot with token: AmigoBot") bot = TelegramBot(TOKEN) await bot.start_polling() From 104265d14abb7bc1ea9cd61d4f230b677828d6b6 Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 13:59:08 +0400 Subject: [PATCH 09/11] Resolved flake8 warnings --- src/Logger/Logger.py | 1 + src/Logger/exceptionHandler.py | 1 + src/bot/file_receiver.py | 9 ++++++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Logger/Logger.py b/src/Logger/Logger.py index 2bb3f5c..c6cd242 100644 --- a/src/Logger/Logger.py +++ b/src/Logger/Logger.py @@ -1,5 +1,6 @@ from abc import abstractmethod, ABCMeta + class Logger(metaclass=ABCMeta): @abstractmethod def log_error(self, error): diff --git a/src/Logger/exceptionHandler.py b/src/Logger/exceptionHandler.py index 89b6887..9e0e758 100644 --- a/src/Logger/exceptionHandler.py +++ b/src/Logger/exceptionHandler.py @@ -1,6 +1,7 @@ from functools import wraps from src.Logger.FileSystemLoguruLogger import MainLogger + def handle_exceptions(func): @wraps(func) def wrapper(*args, **kwargs): diff --git a/src/bot/file_receiver.py b/src/bot/file_receiver.py index a36ba5c..6e1cc39 100644 --- a/src/bot/file_receiver.py +++ b/src/bot/file_receiver.py @@ -1,4 +1,3 @@ -import logging from aiogram import types from src.helperModules.definitions import MB @@ -69,7 +68,11 @@ def create_metadata(self, message: types.Message): sender = message.from_user sender_id = sender.id if sender else None - sender_username = f"@{sender.username}" if sender and sender.username else "No username" + if sender and sender.username: + sender_username = f"@{sender.username}" + else: + sender_username = "No username" + sender_name = sender.first_name if sender else "No name" if sender and sender.last_name: sender_name += f" {sender.last_name}" @@ -101,4 +104,4 @@ def get_file_size(self, message: types.Message): elif message_type == "video": return message.video.file_size else: - return 0 # No file size for other types (like link or text) \ No newline at end of file + return 0 # No file size for other types (like link or text) From f3b2869c9d66bbfefc0ac7e97c118c9f5e134b9e Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 15:33:14 +0400 Subject: [PATCH 10/11] Making CI/CD work again with new loggings --- .github/workflows/docker-build-test.yml | 7 ++++--- src/bot/file_receiver.py | 2 +- src/bot/main.py | 7 +++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker-build-test.yml b/.github/workflows/docker-build-test.yml index 03d2d6a..033b7d6 100644 --- a/.github/workflows/docker-build-test.yml +++ b/.github/workflows/docker-build-test.yml @@ -19,17 +19,18 @@ jobs: - name: Run Docker Container run: | - docker run -d --name telegram_bot telegram_bot_docker + docker run -d --name telegram_bot -e STATUS_FILE_PATH=/tmp/bot_status.txt telegram_bot_docker - name: Sleep For a Short Time run: sleep 30s # Wait for a short time to let the bot start - - name: Check Logs for Bot Start + - name: Check Status File for Bot Start run: | - if docker logs telegram_bot | grep -q "Bot STARTED"; then + if docker exec telegram_bot [ -f /tmp/bot_status.txt ]; then echo "Bot started successfully" docker stop telegram_bot else echo "Bot did not start successfully" + docker logs telegram_bot # Print the logs for debugging exit 1 fi diff --git a/src/bot/file_receiver.py b/src/bot/file_receiver.py index 6e1cc39..54cb349 100644 --- a/src/bot/file_receiver.py +++ b/src/bot/file_receiver.py @@ -72,7 +72,7 @@ def create_metadata(self, message: types.Message): sender_username = f"@{sender.username}" else: sender_username = "No username" - + sender_name = sender.first_name if sender else "No name" if sender and sender.last_name: sender_name += f" {sender.last_name}" diff --git a/src/bot/main.py b/src/bot/main.py index c60887b..b4a44e0 100644 --- a/src/bot/main.py +++ b/src/bot/main.py @@ -1,4 +1,5 @@ import asyncio +import os # aiogram modules from aiogram import Bot, Dispatcher, types @@ -11,6 +12,8 @@ from src.bot.file_receiver import FileReceiver from src.helperModules.definitions import TOKEN +STATUS_FILE_PATH = os.getenv("STATUS_FILE_PATH", "/tmp/bot_status.txt") + class TelegramBot: def __init__(self, token: str): @@ -19,6 +22,10 @@ def __init__(self, token: str): self.file_receiver = FileReceiver() MainLogger.log_info("Bot STARTED") + # Create a status file + with open(STATUS_FILE_PATH, "w") as f: + f.write("Bot STARTED") + # Register the content handler self.dp.message.register(self.content_handler) From 7ebfa82e211c33f72ceef25732f3feb8f04c8a78 Mon Sep 17 00:00:00 2001 From: funkvay-star Date: Fri, 17 May 2024 16:06:27 +0400 Subject: [PATCH 11/11] Better logging structure for more readablity --- .flake8 | 2 ++ src/Logger/FileSystemLoguruLogger.py | 53 +++++++++++++++++++++++----- src/bot/file_receiver.py | 14 ++++++-- token.txt | 1 - 4 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 .flake8 delete mode 100644 token.txt diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..eeb6536 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 85 \ No newline at end of file diff --git a/src/Logger/FileSystemLoguruLogger.py b/src/Logger/FileSystemLoguruLogger.py index 6be9f93..bdcbd81 100644 --- a/src/Logger/FileSystemLoguruLogger.py +++ b/src/Logger/FileSystemLoguruLogger.py @@ -14,13 +14,44 @@ def __init__(self): os.makedirs(log_dir) self._log_path = os.path.join(log_dir, "application.log") print(f"Log path: {self._log_path}") + + # Remove any default handlers logger.remove() - logger.add(sys.stderr, level="DEBUG") - logger.add(self._log_path, - format="{time} {level} {message}", - backtrace=True, - rotation=self._rotate_logs, - retention="10 days") # Keep log files for 10 days + + # Standard logging configuration + logger.add( + sys.stderr, + level="DEBUG", + format="{time} {level} " + "{name}:{function}:" + "{line} - {message}", + filter=lambda record: not record["extra"].get("metadata_block", False) + ) + logger.add( + self._log_path, + format="{time} {level} " + "{name}:{function}:" + "{line} - {message}", + filter=lambda record: not record["extra"].get("metadata_block", False), + rotation=self._rotate_logs, + retention="10 days" + ) + + # Special handler for metadata block + logger.add( + sys.stderr, + level="DEBUG", + format="{message}", + filter=lambda record: record["extra"].get("metadata_block", False) + ) + logger.add( + self._log_path, + format="{message}", + filter=lambda record: record["extra"].get("metadata_block", False), + rotation=self._rotate_logs, + retention="10 days" + ) + logger.info(f"Logger initialized. Log path: {self._log_path}") def log_error(self, error: Exception): @@ -29,8 +60,11 @@ def log_error(self, error: Exception): def log_warning(self, message): logger.warning(message) - def log_info(self, message): - logger.info(message) + def log_info(self, message, **kwargs): + if kwargs: + logger.bind(**kwargs).info(message) + else: + logger.bind(metadata_block=False).info(message) def log_debug(self, message): logger.debug(message) @@ -44,5 +78,8 @@ def _rotate_logs(self, message, file): return True # Rotate the log file return False # Don't rotate the log file + def context(self, **kwargs): + return logger.contextualize(**kwargs) + MainLogger = FileSystemLoguruLogger() diff --git a/src/bot/file_receiver.py b/src/bot/file_receiver.py index 54cb349..6efc336 100644 --- a/src/bot/file_receiver.py +++ b/src/bot/file_receiver.py @@ -1,6 +1,9 @@ from aiogram import types +import json +# helper modules from src.helperModules.definitions import MB + # our modules from src.helperModules.message_helper import MessageHelper from src.Logger.FileSystemLoguruLogger import MainLogger @@ -93,8 +96,15 @@ def create_metadata(self, message: types.Message): return metadata def log_metadata(self, metadata): - for key, value in metadata.items(): - MainLogger.log_info(f"{key}: {value}") + with MainLogger.context(metadata_block=True): + metadata_log = { + "event": "metadata_logging", + "details": metadata + } + MainLogger.log_info( + json.dumps(metadata_log, indent=2), + metadata_block=True + ) def get_file_size(self, message: types.Message): message_type = MessageHelper.determine_message_type(message) diff --git a/token.txt b/token.txt deleted file mode 100644 index fa43a20..0000000 --- a/token.txt +++ /dev/null @@ -1 +0,0 @@ -6926057907:AAGrOIUOUn-KpffUf3RGLNCxiv6srAirQLc \ No newline at end of file