Как получать трейсбек в infinity_polling telebot?

У меня есть бот на телеботе и мне нужно, чтобы он в логи отправлял полную строку с трейсбеком, но он этого не делает. Мне в чате по телеботу сказали сделать дебаг лвл везде, но он по прежнему не отправляет мне трейсбек, только само сообщение об ошибке.

log_dir = r'/root/WorkFolder/logs/'

if not os.path.exists(log_dir):
    os.mkdir(log_dir)

# Создаем объект логгера
logger = logging.getLogger("Bot Logger")
logger.setLevel(logging.DEBUG)  

# Создаем обработчик RotatingFileHandler для записи логов в файлы по дням
logname = os.path.join(log_dir, "Roblox_bot_log.log")
handler = TimedRotatingFileHandler(logname, when="midnight", backupCount=10)
handler.suffix = "%Y%m%d"
handler.setLevel(logging.DEBUG)

# Форматируем сообщения логов

BASEDTFORMAT = "%d.%m.%y %H:%M:%S"
FLN = "[%(levelname)s  %(asctime)s] [%(name)s] - %(funcName)s %(threadName)s " \
  "%(filename)s:%(lineno)d: "
FLNC = "%(filename)s:%(lineno)04d: %(funcName)-12s %(threadName)s " \
  "%(levelname)9s %(asctime)s\n"
MSG = "%(message)s"


formatter = logging.Formatter(FLN + MSG, BASEDTFORMAT)
handler.setFormatter(formatter)

# Добавляем обработчик в логгер
logger.addHandler(handler)
telebot_logger.addHandler(handler)
telebot_logger.setLevel(logging.DEBUG)

logger.info("Logger initialized")

...

И результат логов этого кода

[ERROR  02.01.25 13:32:14] [TeleBot] - _run_middlewares_and_handler WorkerThread1 __init__.py:9227: name 'refferer' is not defined

Я в тупике. Я не знаю, как мне выбить из него трейсбек. Если я ставлю дебаг, то сыпет много лишнего и по прежнему не даёт трейсбеки.


Ответы (1 шт):

Автор решения: Amgarak

Идём в документацию и смотрим какие там есть параметры у логгера. Находим параметр exc_info и читаем описание:

exc_info (tuple[type[BaseException], BaseException, types.TracebackType] | None) – An exception tuple with the current exception information, as returned by sys.exc_info(), or None if no exception information is available.

Отсюда узнаем что если поставить флаг в True, то трейсбек нам покажут, проверяем на простом примере:

import logging

x = 3
y = 0

try:
    x / y
except ZeroDivisionError as err:
    logging.error("exc_info=False")
    logging.error("exc_info=True", exc_info=True)

Вывод:

ERROR:root:exc_info=False
ERROR:root:exc_info=True
Traceback (most recent call last):
  File "<string>", line 7, in <module>
ZeroDivisionError: division by zero

[Program finished]

Теперь нужно решить проблему с самой библиотекой.

Метод logging.getLogger("TeleBot") по названию вернёт экземпляр логгера самой библиотеки, так как при импорте он уже будет проинициализирован. Так что можно смело его закостомить:

import logging
from telebot import TeleBot

telebot_logger = logging.getLogger("TeleBot")
telebot_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

telebot_logger.addHandler(console_handler)

bot = TeleBot("Token")

@bot.message_handler(commands=['start'])
def handle_start_help(message):
    raise ValueError("Test ERROR!")

try:
    bot.polling()
except Exception as e:
    telebot_logger.error("Upss!", exc_info=True)

Вывод:

2025-01-02 15:06:30,682 (<string>:20 MainThread) ERROR - TeleBot: "Upss!"
Traceback (most recent call last):
  File "<string>", line 18, in <module>
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 1178, in polling
    self.__threaded_polling(non_stop=non_stop, interval=interval, timeout=timeout, long_polling_timeout=long_polling_timeout,
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 1253, in __threaded_polling
    raise e
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 1215, in __threaded_polling
    self.worker_pool.raise_exceptions()
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/util.py", line 150, in raise_exceptions
    raise self.exception_info
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/util.py", line 93, in run
    task(*args, **kwargs)
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 8623, in _run_middlewares_and_handler
    result = handler['function'](message)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 15, in handle_start_help
ValueError: Test ERROR!
Upss!
Traceback (most recent call last):
  File "<string>", line 18, in <module>
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 1178, in polling
    self.__threaded_polling(non_stop=non_stop, interval=interval, timeout=timeout, long_polling_timeout=long_polling_timeout,
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 1253, in __threaded_polling
    raise e
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 1215, in __threaded_polling
    self.worker_pool.raise_exceptions()
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/util.py", line 150, in raise_exceptions
    raise self.exception_info
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/util.py", line 93, in run
    task(*args, **kwargs)
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 8623, in _run_middlewares_and_handler
    result = handler['function'](message)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 15, in handle_start_help
ValueError: Test ERROR!

[Program finished]

Для infinity_polling предлагаю обходной манёвр. При инициализации класса TeleBot можно в параметре exception_handler задать собственный обработчик исключений:

import telebot
import logging
from telebot import TeleBot

telebot_logger = logging.getLogger("TeleBot")
#telebot_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
telebot_logger.addHandler(console_handler)

class MyExceptionHandler(telebot.ExceptionHandler):
    def handle(self, exception):
        telebot_logger.error("Upss!", exc_info=True)
        return True # Если False - выведет полный стек-трейс
 
bot = telebot.TeleBot('Token', exception_handler=MyExceptionHandler())

@bot.message_handler(commands=['start'])
def handle_start_help(message):
    raise ValueError("Test exception in start handler!")  

bot.infinity_polling()

Вывод:

2025-01-02 15:50:54,106 (<string>:13 WorkerThread1) ERROR - TeleBot: "Upss!"
Traceback (most recent call last):
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/util.py", line 93, in run
    task(*args, **kwargs)
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 8623, in _run_middlewares_and_handler
    result = handler['function'](message)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 21, in handle_start_help
ValueError: Test exception in start handler!
Upss!
Traceback (most recent call last):
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/util.py", line 93, in run
    task(*args, **kwargs)
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.11/site-packages/telebot/__init__.py", line 8623, in _run_middlewares_and_handler
    result = handler['function'](message)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 21, in handle_start_help
ValueError: Test exception in start handler!
→ Ссылка