From 04391cded9a59afd5ab3c0d420cd01e89f3fe4d7 Mon Sep 17 00:00:00 2001 From: Yap Han Chiang Date: Thu, 31 Aug 2023 21:19:04 +0800 Subject: [PATCH] Feature/logging (#54) * Replace print with logging * log --- src/db/redis.py | 7 +++++-- src/dependencies.py | 7 +++++-- src/event/event_emitter.py | 10 +++++++--- src/job/crypto/crypto.py | 11 ++++++----- src/job/job_wrapper.py | 9 +++++---- src/job/message_sender_wrapper.py | 11 ++++++----- src/job/stocks/sentiment_message_sender.py | 5 ++++- src/job/stocks/stocks.py | 6 ++++-- src/job/stocks/tradingview_message_sender.py | 3 +++ .../telegram_notification.py | 17 ++++++++++------- src/router/tradingview/tradingview.py | 13 ++++++++----- .../vix_central/thirdparty_vix_central.py | 6 +++++- src/service/chainanalysis.py | 4 +++- src/service/tradingview_service.py | 5 ++++- src/service/vix_central.py | 6 ++++-- src/third_party_service/messari.py | 4 +++- src/third_party_service/vix_central.py | 7 +++++-- src/util/context_manager.py | 7 ++++--- src/util/exception.py | 12 ++++++++++++ 19 files changed, 103 insertions(+), 47 deletions(-) create mode 100644 src/util/exception.py diff --git a/src/db/redis.py b/src/db/redis.py index 941c23ac..43d0d0e2 100644 --- a/src/db/redis.py +++ b/src/db/redis.py @@ -1,7 +1,10 @@ +import logging + import redis.asyncio as redis from src.config import config +logger = logging.getLogger('Redis') class Redis: redis: redis.Redis @@ -11,11 +14,11 @@ def get_client(): @staticmethod async def start_redis(): - print('starting redis') + logger.info('starting redis') host = config.get_redis_host() Redis.redis = await redis.Redis(host=host, port=config.get_redis_port(), db=config.get_redis_db()) @staticmethod async def stop_redis(): - print('stopping redis') + logger.info('stopping redis') await Redis.redis.close() \ No newline at end of file diff --git a/src/dependencies.py b/src/dependencies.py index db8ca801..64c82d3a 100644 --- a/src/dependencies.py +++ b/src/dependencies.py @@ -1,3 +1,5 @@ +import logging + from src.service.barchart import BarchartService from src.service.crypto_sentiment import CryptoSentimentService from src.service.stocks_sentiment import StocksSentimentService @@ -11,6 +13,7 @@ from src.third_party_service.vix_central import ThirdPartyVixCentralService from src.service.vix_central import VixCentralService +logger = logging.getLogger('Dependencies') class Dependencies: is_initialised: bool = False @@ -56,9 +59,9 @@ async def build(): Dependencies.crypto_sentiment_service = CryptoSentimentService() Dependencies.is_initialised = True - print('Dependencies built') + logger.info('Dependencies built') else: - print('Dependencies has already been initialised') + logger.info('Dependencies has already been initialised') @staticmethod async def cleanup(): diff --git a/src/event/event_emitter.py b/src/event/event_emitter.py index af1ee3bd..5617e6af 100644 --- a/src/event/event_emitter.py +++ b/src/event/event_emitter.py @@ -1,14 +1,17 @@ +import logging from pyee.asyncio import AsyncIOEventEmitter from src.notification_destination import telegram_notification from src.type.market_data_type import MarketDataType from src.util.my_telegram import escape_markdown +from src.util.exception import get_exception_message async_ee = AsyncIOEventEmitter() +logger = logging.getLogger('Event emitter') @async_ee.on('error') async def on_error(message): - print(f"event emitter error: {message}") + logger.error(f"event emitter error: {message}") await telegram_notification.send_message_to_admin(escape_markdown(str(f'event emitter error: {message}')), market_data_type=MarketDataType.STOCKS) @async_ee.on('send_to_telegram') @@ -17,10 +20,11 @@ async def send_to_telegram_handler(*args, **kwargs): channel = kwargs['channel'] message = kwargs['message'] market_data_type = kwargs['market_data_type'] + raise RuntimeError("oops error") res = await telegram_notification.send_message_to_channel(message=message, chat_id=channel, market_data_type=market_data_type) if res: telegram_notification.print_telegram_message(res) except Exception as e: - print(e) + logger.error(f"{get_exception_message(e)}") market_data_type = kwargs['market_data_type'] or MarketDataType.STOCKS - await telegram_notification.send_message_to_admin(escape_markdown(str(e)), market_data_type=market_data_type) + await telegram_notification.send_message_to_admin(f"{escape_markdown(str(e))}, stack: {escape_markdown(tb)}", market_data_type=market_data_type) diff --git a/src/job/crypto/crypto.py b/src/job/crypto/crypto.py index 5520387d..7839d3e7 100644 --- a/src/job/crypto/crypto.py +++ b/src/job/crypto/crypto.py @@ -1,4 +1,5 @@ import asyncio +import logging from src.job.crypto.chain_analysis_message_sender import ChainAnalysisMessageSender from src.job.crypto.messari_message_sender import MessariMessageSender @@ -10,6 +11,7 @@ # TODO: test +logger = logging.getLogger('Crypto notification job') class CryptoNotificationJob(JobWrapper): # run at 8.45am, 4.15pm def should_run(self) -> bool: @@ -31,15 +33,14 @@ def should_run(self) -> bool: local = local.replace(hour=local_hour_int, minute=local_minute_int) delta = now - local should_run = abs(delta.total_seconds()) <= config.get_job_delay_tolerance_second() + logger.info( + f'local time: {local}, current time: {now}, local hour to run: {local_hour_int}, local minute to run: {local_minute_int}, current hour {now.hour}, current minute: {now.minute}, delta second: {delta.total_seconds()}, should run: {should_run}') if should_run: - print( - f'local time: {local}, current time: {now}, local hour to run: {local_hour_int}, local minute to run: {local_minute_int}, current hour {now.hour}, current minute: {now.minute}, delta second: {delta.total_seconds()}, should run: {should_run}') return should_run - print( - f'local time: {local}, current time: {now}, local hour to run: {local_hour_int}, local minute to run: {local_minute_int}, current hour {now.hour}, current minute: {now.minute}, delta second: {delta.total_seconds()}, should run: {should_run}') return should_run + @property def message_senders(self): return [MessariMessageSender(), ChainAnalysisMessageSender(), SentimentMessageSender()] @@ -53,4 +54,4 @@ def market_data_type(self): loop = asyncio.get_event_loop() job = CryptoNotificationJob() data = asyncio.run(job.start()) - print(data) \ No newline at end of file + logger.info(data) \ No newline at end of file diff --git a/src/job/job_wrapper.py b/src/job/job_wrapper.py index 28218368..ed1bb41d 100644 --- a/src/job/job_wrapper.py +++ b/src/job/job_wrapper.py @@ -1,5 +1,5 @@ import argparse -import traceback +import logging from abc import ABC, abstractmethod from typing import List @@ -10,10 +10,12 @@ from src.notification_destination.telegram_notification import send_message_to_channel, \ market_data_type_to_admin_chat_id, init_telegram_bots from src.util.context_manager import TimeTrackerContext +from src.util.exception import get_exception_message from src.util.my_telegram import format_messages_to_telegram, escape_markdown from src.type.market_data_type import MarketDataType +logger = logging.getLogger('Job wrapper') class JobWrapper(ABC): async def start(self): parser = argparse.ArgumentParser(description='Sends daily stock data notification to telegram') @@ -52,9 +54,8 @@ async def start(self): return res except Exception as e: - tb = traceback.format_exc() - print(f"{self.__class__.__name__} exception: {e}, stack: {tb}") - messages.append(f"{escape_markdown(str(e))}, stack: {tb}") + logger.error(get_exception_message(e, cls=self.__class__.__name__)) + messages.append(f"{get_exception_message(e, cls=self.__class__.__name__, should_escape_markdown=True)}") message = format_messages_to_telegram(messages) await send_message_to_channel(message=message, chat_id=market_data_type_to_admin_chat_id[self.market_data_type], market_data_type=self.market_data_type) diff --git a/src/job/message_sender_wrapper.py b/src/job/message_sender_wrapper.py index 9a4a4ed3..ba71936c 100644 --- a/src/job/message_sender_wrapper.py +++ b/src/job/message_sender_wrapper.py @@ -1,19 +1,21 @@ -import traceback +import logging from abc import ABC, abstractmethod from typing import List from src.notification_destination.telegram_notification import send_message_to_channel, \ market_data_type_to_admin_chat_id, market_data_type_to_chat_id +from src.util.exception import get_exception_message from src.util.my_telegram import escape_markdown, format_messages_to_telegram +logger = logging.getLogger('Message sender wrapper') class MessageSenderWrapper(ABC): async def start(self): try: messages = await self.format_message() if messages is None or len(messages) == 0: - print(f"No message to send for market data type: {self.market_data_type}, data source: {self.data_source}") + logger.warning(f"No message to send for market data type: {self.market_data_type}, data source: {self.data_source}") return telegram_message = format_messages_to_telegram(messages) @@ -22,9 +24,8 @@ async def start(self): market_data_type=self.market_data_type) return res except Exception as e: - tb = traceback.format_exc() - print(f"{self.__class__.__name__} exception: {e}, stack: {tb}") - messages = [f"{escape_markdown(str(e))}, stack: {tb}"] + logger.error(get_exception_message(e, cls=self.__class__.__name__)) + messages = [f"{get_exception_message(e, cls=self.__class__.__name__, should_escape_markdown=True)}"] message = format_messages_to_telegram(messages) await send_message_to_channel(message=message, chat_id=market_data_type_to_admin_chat_id[self.market_data_type], market_data_type=self.market_data_type) diff --git a/src/job/stocks/sentiment_message_sender.py b/src/job/stocks/sentiment_message_sender.py index 3032d43b..8fae488d 100644 --- a/src/job/stocks/sentiment_message_sender.py +++ b/src/job/stocks/sentiment_message_sender.py @@ -1,3 +1,5 @@ +import logging + from src.dependencies import Dependencies from src.job.message_sender_wrapper import MessageSenderWrapper from src.type.sentiment import FearGreedResult @@ -5,6 +7,7 @@ from src.util.my_telegram import escape_markdown import src.util.date_util as date_util +logger = logging.getLogger('Stocks sentiment message sender') class StocksSentimentMessageSender(MessageSenderWrapper): @property def data_source(self): @@ -29,7 +32,7 @@ async def format_message(self): if message is not None: messages.append(message) - print(messages) + logger.info(messages) return messages diff --git a/src/job/stocks/stocks.py b/src/job/stocks/stocks.py index 548acdcf..7cc7b197 100644 --- a/src/job/stocks/stocks.py +++ b/src/job/stocks/stocks.py @@ -1,4 +1,5 @@ import asyncio +import logging from src.job.job_wrapper import JobWrapper from src.job.stocks.sentiment_message_sender import StocksSentimentMessageSender @@ -9,6 +10,7 @@ from src.type.market_data_type import MarketDataType # TODO: test +logger = logging.getLogger('Stocks notification job') class StocksNotificationJob(JobWrapper): # run at 8.45am def should_run(self) -> bool: @@ -22,7 +24,7 @@ def should_run(self) -> bool: delta = now - local should_run = abs(delta.total_seconds()) <= config.get_job_delay_tolerance_second() - print( + logger.info( f'local time: {local}, current time: {now}, local hour to run: {config.get_stocks_job_start_local_hour()}, local minute to run: {config.get_stocks_job_start_local_minute()}, current hour {now.hour}, current minute: {now.minute}, delta second: {delta.total_seconds()}, should run: {should_run}') return should_run @@ -43,4 +45,4 @@ def market_data_type(self): loop = asyncio.get_event_loop() job = StocksNotificationJob() data = asyncio.run(job.start()) - print(data) \ No newline at end of file + logger.info(data) \ No newline at end of file diff --git a/src/job/stocks/tradingview_message_sender.py b/src/job/stocks/tradingview_message_sender.py index db527c19..1368c54b 100644 --- a/src/job/stocks/tradingview_message_sender.py +++ b/src/job/stocks/tradingview_message_sender.py @@ -1,4 +1,5 @@ import datetime +import logging from typing import List from src.dependencies import Dependencies @@ -13,6 +14,7 @@ from src.util.sleep import sleep +logger = logging.getLogger('Trading view message sender') class TradingViewMessageSender(MessageSenderWrapper): @property def data_source(self): @@ -40,6 +42,7 @@ async def format_message(self): most_recent_day = get_most_recent_non_weekend_or_today(now - datetime.timedelta(days=1)) time_diff = abs(int(most_recent_day.timestamp()) - tradingview_stocks_data.score) if not config.get_is_testing_telegram() and time_diff > 86400: + logger.info(f'Skip formatting message. is testing telegram: {config.get_is_testing_telegram()}, time difference: {time_diff}') return messages tradingview_economy_indicator_data = await self.tradingview_service.get_tradingview_daily_stocks_data( diff --git a/src/notification_destination/telegram_notification.py b/src/notification_destination/telegram_notification.py index 4d9b994d..95f183e8 100644 --- a/src/notification_destination/telegram_notification.py +++ b/src/notification_destination/telegram_notification.py @@ -1,6 +1,9 @@ +import logging + import telegram import src.config.config as config from src.type.market_data_type import MarketDataType +from src.util.exception import get_exception_message from src.util.my_telegram import escape_markdown # TODO: Clean up @@ -16,9 +19,11 @@ market_data_type_to_admin_chat_id = {} market_data_type_to_chat_id = {} +logger = logging.getLogger('Telegram notification') + def init_telegram_bots(): global stocks_bot, stocks_admin_bot, stocks_dev_bot, crypto_bot, crypto_admin_bot, crypto_dev_bot - print('Initialising telegram bots') + logger.info('Initialising telegram bots') stocks_bot = telegram.Bot(token=config.get_telegram_stocks_bot_token()) stocks_admin_bot = telegram.Bot(token=config.get_telegram_stocks_admin_bot_token()) stocks_dev_bot = telegram.Bot(token=config.get_telegram_stocks_dev_bot_token()) @@ -45,15 +50,13 @@ def init_telegram_bots(): - - async def send_message_to_channel(message: str, chat_id, market_data_type: MarketDataType): if config.get_disable_telegram(): - print('Telegram is disabled') + logger.info('Telegram is disabled') return if market_data_type is None: - print('market_data_type is not passed in') + logger.warning('market_data_type is not passed in') return if config.get_is_testing_telegram() or config.get_simulate_tradingview_traffic(): @@ -63,7 +66,7 @@ async def send_message_to_channel(message: str, chat_id, market_data_type: Marke res = await chat_id_to_telegram_client[chat_id].send_message(chat_id, text=message, parse_mode='MarkdownV2') return res except Exception as e: - print(e) + logger.error(get_exception_message(e)) await chat_id_to_telegram_client[chat_id].send_message(chat_id, text=escape_markdown(str(e)), parse_mode='MarkdownV2') async def send_message_to_admin(message: str, market_data_type: MarketDataType): @@ -83,4 +86,4 @@ def get_dev_channel_id_from_market_data_type(market_data_type: MarketDataType): return config.get_telegram_stocks_dev_id() def print_telegram_message(res: telegram.Message): - print(f"Sent to {res.chat.title} {res.chat.type} at {res.date}. Message id {res.id}") \ No newline at end of file + logging.info(f"Sent to {res.chat.title} {res.chat.type} at {res.date}. Message id {res.id}") \ No newline at end of file diff --git a/src/router/tradingview/tradingview.py b/src/router/tradingview/tradingview.py index f446d1fa..d56ff47d 100644 --- a/src/router/tradingview/tradingview.py +++ b/src/router/tradingview/tradingview.py @@ -1,5 +1,6 @@ import asyncio import json +import logging from fastapi import APIRouter, Request @@ -9,11 +10,13 @@ from src.type.market_data_type import MarketDataType from src.type.trading_view import TradingViewDataType from src.util.date_util import get_current_date +from src.util.exception import get_exception_message from src.util.my_telegram import format_messages_to_telegram, escape_markdown from src.util.sleep import sleep router = APIRouter(prefix="/tradingview") +logger = logging.getLogger('Trading view') @router.post("/daily-stocks") async def tradingview_daily_stocks_data(request: Request): # for economy_indicator type, there is no ema20s, volumes @@ -27,10 +30,10 @@ async def tradingview_daily_stocks_data(request: Request): try: body = await request.json() filtered_body = filter_tradingview_request_body(body) - print(filtered_body) + logger.info(filtered_body) except Exception as e: - print(e) - messages.append(f"JSON body error: {escape_markdown(str(e))}") + logger.error(get_exception_message(e)) + messages.append(f"JSON body error: {get_exception_message(e, should_escape_markdown=True)}") message = format_messages_to_telegram(messages) async_ee.emit('send_to_telegram', message=message, channel=config.get_telegram_stocks_admin_id(), market_data_type=MarketDataType.STOCKS) return {"data": "OK"} @@ -80,7 +83,7 @@ async def tradingview_daily_stocks_data(request: Request): save_message = f'Successfully saved trading view data for type: *{escape_markdown(filtered_body.get("type"))}* at *{escape_markdown(str(now))}*, key: *{escape_markdown(key)}*, score: *{timestamp}*, days to store: *{config.get_trading_view_days_to_store()}*' messages.append(save_message) - print(f'Successfully saved trading view data for {str(now)}, key: {key}, score: {timestamp}, days to store: {config.get_trading_view_days_to_store()}, data: {json_data}') + logger.info(f'Successfully saved trading view data for {str(now)}, key: {key}, score: {timestamp}, days to store: {config.get_trading_view_days_to_store()}, data: {json_data}') # sleep for a bit, telegram client will timeout if concurrent requests come in # await sleep() async_ee.emit('send_to_telegram', message=format_messages_to_telegram(messages), channel=config.get_telegram_stocks_admin_id(), market_data_type=MarketDataType.STOCKS) @@ -93,7 +96,7 @@ async def tradingview_daily_stocks_data(request: Request): async def reset_is_testing_telegram(original_value: str, delay: int = 3): await asyncio.sleep(delay) - print(f'Set is_telegram_telegram to original value {original_value} after sleeping for {delay} seconds') + logger.info(f'Set is_telegram_telegram to original value {original_value} after sleeping for {delay} seconds') config.set_is_testing_telegram(original_value) def filter_tradingview_request_body(body: dict) -> dict: diff --git a/src/router/vix_central/thirdparty_vix_central.py b/src/router/vix_central/thirdparty_vix_central.py index fb6fac21..8cc712c8 100644 --- a/src/router/vix_central/thirdparty_vix_central.py +++ b/src/router/vix_central/thirdparty_vix_central.py @@ -1,8 +1,12 @@ +import logging + from fastapi import APIRouter, Response, status from src.dependencies import Dependencies +from src.util.exception import get_exception_message router = APIRouter(prefix="/thirdparty/vixcentral") +logger = logging.getLogger('Third party vix central') @router.get("/current") async def get_current(): thirdparty_vix_central_service = Dependencies.get_thirdparty_vix_central_service() @@ -22,5 +26,5 @@ async def get_historical(date: str, response: Response): res = await thirdparty_vix_central_service.get_historical(date=date) return {"data": res} except Exception as e: - print(e) + logger.error(get_exception_message(e)) return {"error": str(e)} diff --git a/src/service/chainanalysis.py b/src/service/chainanalysis.py index 59041a25..210c0ac7 100644 --- a/src/service/chainanalysis.py +++ b/src/service/chainanalysis.py @@ -1,9 +1,11 @@ import asyncio +import logging from dataclasses import dataclass from typing import List from src.third_party_service.chainanalysis import ThirdPartyChainAnalysisService +logger = logging.getLogger('Chain analysis servoce') @dataclass class UnitValue: @@ -60,7 +62,7 @@ async def get_fees(self, symbol: str) -> ChainAnalysisFees: generation_summary = summary.get('generation', []) fees_summary = next(filter(lambda x: x['name'].lower() == 'btc fees', generation_summary), None) if fees_summary is not None: - print(f'Fees summary for {symbol}: {fees_summary}') + logger.info(f'Fees summary for {symbol}: {fees_summary}') main_fees = fees.get('data', {}).get('main', {}) unix_ts_list = list(main_fees.keys()) diff --git a/src/service/tradingview_service.py b/src/service/tradingview_service.py index 1d7b6dfc..6dfb3c87 100644 --- a/src/service/tradingview_service.py +++ b/src/service/tradingview_service.py @@ -1,10 +1,13 @@ import json +import logging from typing import List, Optional from src.config import config from src.db.redis import Redis from src.type.trading_view import TradingViewDataType, TradingViewData, TradingViewStocksData, TradingViewRedisData +from src.util.exception import get_exception_message +logger = logging.getLogger('Trading view service') class TradingViewService: async def get_tradingview_daily_stocks_data(self, type: TradingViewDataType) -> Optional[TradingViewRedisData]: try: @@ -15,7 +18,7 @@ async def get_tradingview_daily_stocks_data(self, type: TradingViewDataType) -> data_parsed = json.loads(tradingview_data[0][0]) return TradingViewRedisData(key=key, data=self.hydrate_tradingview_data(data_parsed), score=int(tradingview_data[0][1])) except Exception as e: - print(e) + logger.error(get_exception_message(e, cls=self.__class__.__name__, should_escape_markdown=True)) return None # score = timestamp of current date(without time) diff --git a/src/service/vix_central.py b/src/service/vix_central.py index d0ae35e7..64e59253 100644 --- a/src/service/vix_central.py +++ b/src/service/vix_central.py @@ -1,5 +1,6 @@ import datetime import asyncio +import logging from typing import List from src.config import config from src.third_party_service.vix_central import ThirdPartyVixCentralService @@ -39,6 +40,7 @@ def clear_current_value(self): if len(self.vix_futures_values) > 1: self.vix_futures_values.pop(0) +logger = logging.getLogger('Vix central service') class VixCentralService: # month of the vix futures we are interested in. e.g. "Jan" MONTH_OF_INTEREST = None @@ -65,11 +67,11 @@ async def get_recent_values(self) -> RecentVixFuturesValues: current_date = date_util.get_most_recent_non_weekend_or_today(date_util.get_current_datetime()) # historical data doesn't change, just need to fetch current data if len(self.recent_values.vix_futures_values) == self.number_of_days_to_store - 1: - print('Refreshing current vix central data') + logger.info('Refreshing current vix central data') current = await self.third_party_service.get_current() self.recent_values.vix_futures_values.insert(0, self._current_to_vix_futures_value(current, current_date=current_date)) else: - print('Retrieving current and historical vix central data') + logger.info('Retrieving current and historical vix central data') current = await self.third_party_service.get_current() self.recent_values.vix_futures_values.insert(0, self._current_to_vix_futures_value(current, current_date=current_date)) historical_dates = [] diff --git a/src/third_party_service/messari.py b/src/third_party_service/messari.py index e186dcc1..baabaee0 100644 --- a/src/third_party_service/messari.py +++ b/src/third_party_service/messari.py @@ -1,4 +1,5 @@ import json +import logging import urllib.parse import re @@ -7,6 +8,7 @@ from src.http_client import HttpClient +logger = logging.getLogger('Third party message service') class ThirdPartyMessariService: BASE_URL = 'https://graphql.messari.io' @@ -68,7 +70,7 @@ async def get_metrics(self, symbol: str): res = await self.http_client.get(url=url) if res.status != 200: - print(res.text) + logging.info(res.text) res.raise_for_status() res_json = await res.json() return res_json \ No newline at end of file diff --git a/src/third_party_service/vix_central.py b/src/third_party_service/vix_central.py index c306f11e..3cba5b5f 100644 --- a/src/third_party_service/vix_central.py +++ b/src/third_party_service/vix_central.py @@ -1,8 +1,11 @@ +import logging + from src.http_client import HttpClient # Monday to friday, 24 hours # See: https://www.cboe.com/tradable_products/vix/vix_futures/specifications/ +logger = logging.getLogger('Third party vix central service') class ThirdPartyVixCentralService: BASE_URL = 'http://vixcentral.com' HEADERS = { @@ -24,7 +27,7 @@ async def cleanup(self): async def get_current(self): res = await self.http_client.get(url='/ajax_update') if res.status != 200: - print(res.text) + logger.info(res.text) res.raise_for_status() res_json = await res.json() return res_json @@ -37,7 +40,7 @@ async def get_historical(self, date: str): res = await self.http_client.get(url='/ajax_historical', params={"n1": date}) if res.status != 200: - print(res.text) + logger.info(res.text) res.raise_for_status() res_json = await res.json() diff --git a/src/util/context_manager.py b/src/util/context_manager.py index 4bf2dbcc..d31b4e41 100644 --- a/src/util/context_manager.py +++ b/src/util/context_manager.py @@ -1,15 +1,16 @@ +import logging import time from contextlib import ContextDecorator - +logger = logging.getLogger('Time tracker context') class TimeTrackerContext(ContextDecorator): def __init__(self, name: str): self.name = name def __enter__(self): self.start_time = time.time() - print(f'Starting {self.name}') + logger.info(f'Starting {self.name}') def __exit__(self, exc_type, exc_val, exc_tb): time_elapsed = time.time() - self.start_time - print(f'Completed {self.name}. Time taken: {time_elapsed}') \ No newline at end of file + logger.info(f'Completed {self.name}. Time taken: {time_elapsed}') \ No newline at end of file diff --git a/src/util/exception.py b/src/util/exception.py new file mode 100644 index 00000000..2fd6a6b0 --- /dev/null +++ b/src/util/exception.py @@ -0,0 +1,12 @@ +import traceback + +from src.util.my_telegram import escape_markdown + +def get_exception_message(exception: Exception, cls = None, should_escape_markdown = False): + tb = traceback.format_exc() + message = '' + if cls is not None: + message = f'{cls} ' + exp = str(exception) if not should_escape_markdown else escape_markdown(str(exception)) + trace = str(tb) if not should_escape_markdown else escape_markdown(str(tb)) + return f'{message}exception: {exp}, stack trace: {trace}'