Логирование: способ облегчения разработки Telegram-бота

Продолжаю делиться своим небольшим опытом с такими же, как и я начинающими разработчиками Telegram-ботов на Python.

Логирование: способ облегчения разработки Telegram-бота

Мало подключить библиотеку logging в ваш проект, так как не все ошибки это ошибки. Сам охерел от формулировки, поэтому поясню: не все ошибки, с которыми может столкнуться ваш бот являются событиями уровня WARNING, ваш бот попросту может отработать то или иное событие некорректно, но так как по факту оно отработано, это не будет записано в лог.

Для начала создадим отдельный модуль log.py (не называйте модуль logging, так как называть модуль аналогично библиотеке приводит к не очевидной ошибке).

import logging
from logging.handlers import TimedRotatingFileHandler
import os
from datetime import time

logger = logging.getLogger()
logger.setLevel(logging.WARNING)

def start_logging():
if not os.path.exists(‘logs’):
os.makedirs(‘logs’)

handler = TimedRotatingFileHandler(
filename=’logs/log’,
when=’H’,
interval=1,
atTime=time(1, 0),
backupCount=5,
encoding=’utf-8′
)
handler.suffix = ‘%Y-%m-%d.log’
handler.setLevel(logging.WARNING)

formatter = logging.Formatter(‘%(asctime)s — %(levelname)s — %(message)s’)
handler.setFormatter(formatter)

logger.addHandler(handler)

Для начала рекомендую выставлять уровень логирования DEBUG, так как будут записываться все действия бота, вот такая иерархия:

  • Debug — самый низкий уровень логирования, предназначенный для отладки.
  • Info — этот уровень предназначен для вывода данных о фрагментах кода, работающих так, как ожидается.
  • Warning — этот уровень логирования предусматривает вывод предупреждений, он применяется для записи сведений о событиях, на которые программист обычно обращает внимание. Такие события вполне могут привести к проблемам при работе приложения. Если явно не задать уровень логирования — по умолчанию используется именно warning.
  • Error — этот уровень логирования предусматривает вывод сведений об ошибках — о том, что часть приложения работает не так как ожидается, о том, что программа не смогла правильно выполниться.
  • Critical — этот уровень используется для вывода сведений об очень серьёзных ошибках, наличие которых угрожает нормальному функционированию всего приложения. Если не исправить такую ошибку — это может привести к тому, что приложение прекратит работу.

Я использую стандартный уровень WARNING. Так же я указал папку куда сохранять логи и настроил создание нового файла каждый день для удобства чтения.

Теперь я могу добавить запись нужных мне событий в лог с помощью конструкции try-except:

async def get_twitch_token():
try:
response = requests.post(
f»https://id.twitch.tv/oauth2/token?client_id={twitch_id}&client_secret={twitch_key}&grant_type=client_credentials»
)
response.raise_for_status()
return (response.json())[«access_token»]

except Exception as e:
log.logger.exception(f»Ошибка в функции get_twitch_token: {e}»)

return None

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

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

async def log_message(sender, user_id, message):
current_time = datetime.datetime.now()
formatted_time = current_time.strftime(«%Y-%m-%d %H:%M:%S»)
log_entry = f»{formatted_time}: {sender} — {message}»

log_folder = «message_history»

# Создаем папку, если она не существует
if not os.path.exists(log_folder):
os.makedirs(log_folder)

# Создайте файл или откройте существующий для записи
log_file_path = os.path.join(log_folder, f»user_{user_id}_chat_log.txt»)
with open(log_file_path, «a», encoding=»utf-8″) as log_file:
log_file.write(log_entry + «\n»)

Для удобства пусть название файла будет user_id пользователя с которым идёт чат, а сами файлы сохраняются в отдельную папку. В итоге имеем файл «user_116918991_chat_log.txt»

Теперь нам нужно вызвать эту функцию в той части кода, где нам необходимо записать какое-либо сообщение:

@dp.message_handler(commands=’start’)
async def send_start(message: types.Message, user_id=None): # Принимаем user_id как аргумент
user_id = user_id or message.from_user.id # Если user_id не передан, используем его из сообщения
add_and_follow = InlineKeyboardMarkup(row_width=1).add(keyboard.add_channel, keyboard.send_follow)

text = f»🤖 Не пропусти стримы на Twitch!» \
f»\n\n📺Я буду следить за твоими любимыми каналами и уведомлю тебя о начале стримов. 🎮🔔» \
f»\n\nПолучай актуальную информацию о названии, категории и продолжительности стрима прямо в уведомлениях!» \
f»Вся информация обновляется в реальном времени. 💥»

await message.answer(text, reply_markup=add_and_follow)

await log_message(«System», user_id, «Отправлена команда /start»)
await log_message(«Bot», user_id, text)

  • await log_message(«System», user_id, «Отправлена команда /start») — тут я записываю системное сообщение, а именно какое именно действие спровоцировало бота отправить сообщение.
  • await log_message(«Bot», user_id, text) — тут я уже записываю непосредственно сообщение отправленное ботом.

2023-09-18 20:28:32: System — Отправлена команда /start
2023-09-18 20:28:32: Bot — 🤖 Не пропусти стримы на Twitch!

📺Я буду следить за твоими любимыми каналами и уведомлю тебя о начале стримов. 🎮🔔

Получай актуальную информацию о названии, категории и продолжительности стрима прямо в уведомлениях!Вся информация обновляется в реальном времени. 💥

Таким образом необходимо вызвать функцию log_message везде где нам необходимо записать какое-либо действие бота или юзера.

Напомню, моего бота зовут TwitchNotifier, он уведомляет о начале стримов на Twitch. Недавно я реализовал возможность отправки уведомлений в telegram-каналы, о чём планирую рассказать в одном из следующих гайдов. Также он отправляет умные уведомления, которые в реальном времени отображают длительность стрима, название, категорию.

 

Источник

Telegramбота, Логирование, облегчения, разработки, способ

Читайте также