惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
Engineering at Meta
Engineering at Meta
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
B
Blog RSS Feed
GbyAI
GbyAI
P
Proofpoint News Feed
aimingoo的专栏
aimingoo的专栏
MyScale Blog
MyScale Blog
D
Docker
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recorded Future
Recorded Future
美团技术团队
The Register - Security
The Register - Security
V
Visual Studio Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Tailwind CSS Blog
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美
量子位
B
Blog
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
A
About on SuperTechFans
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
雷峰网
雷峰网
大猫的无限游戏
大猫的无限游戏
J
Java Code Geeks
L
LangChain Blog
Latest news
Latest news
S
SegmentFault 最新的问题
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
F
Full Disclosure
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
W
WeLiveSecurity
T
Tenable Blog
T
Tor Project blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Логи, которые реально помогают: как дебажить продакшен-бота
andreypopov3 · 2026-04-30 · via Все публикации подряд на Хабре

Логи, которые реально помогают: как дебажить продакшен-бота

Уровень сложностиСредний

Время на прочтение6 мин

Охват и читатели553

Туториал

Знакомая ситуация: бот вроде бы работает. Люди тыкают кнопки, получают ответы, всё хорошо. Но иногда случается странное.

Прилетает сообщение в поддержку: «Бот не отвечает». Или ещё хуже: «Бот выдал какую‑то ошибку и всё». Вы бежите к терминалу, поднимаете историю... и ничего не видите. Ни ошибки, ни стека, ни даже намёка на то, где именно всё сломалось.

Вы просто слепы.

Без нормальных логов вы не понимаете ровно ничего: обработчик не сработал, API молчит, база данных упала или вы просто забыли зарегистрировать хендлер. Спойлер: я через это проходил, и не раз.

Просто Bot started, а какие будут будущие апдейты - неизвестно

Просто Bot started, а какие будут будущие апдейты - неизвестно

Почему print() не работает

В учебных проектах все пишут так:

print("user clicked button")

Выглядит безобидно. Но когда ваш бот оказывается в продакшене — это просто мусор. Давайте разберёмся, почему.

Когда вы ставите print(), вы лишаете себя контекста. Вы не видите, в какое время это случилось. Вы не знаете, какой пользователь нажал эту кнопку. Вы не можете отфильтровать тысячи сообщений и найти только ошибки. А если бот живёт в докере — этот print просто растворится в общем потоке логов без всякой надежды на поиск.

print() годится только для отладки «на коленке», когда вы сидите и смотрите за ботом вживую. Для продакшена это зло.

Базовая настройка логов (минимум)

В Python есть встроенный модуль logging. И вот вам минимальная конфигурация, которая уже даст вам 80 пользы без лишних танцев с бубном:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(name)s | %(message)s"
)

Что тут происходит. level=logging.INFO значит, что вы видите информационные сообщения и ошибки, но не тонете в DEBUG-шуме. Формат строки добавляет время, уровень, имя модуля и само сообщение. Всё. Уже этого достаточно, чтобы читать логи как историю, а не как кашу.

Где логировать в боте (самое важное)

Логировать всё подряд не надо. Логировать надо то, что помогает понять жизненный цикл запроса.

Входящие события

Каждое сообщение от пользователя должно оставлять след. Я всегда пишу так:

logging.info(f"user={message.from_user.id} text={message.text}")

Теперь я вижу, что конкретный пользователь делал. Когда приходит жалоба «бот не работает», я открываю логи и говорю: «Смотри, последнее сообщение от этого пользователя — 'купить билет', после чего бот позвонил в API и ответа не получил». Без этой строчки я даже не узнаю, дошло ли сообщение до бота.

Действия бота

Бот что‑то делает — бот логирует это. Просто и без sneakers.

logging.info("sending profile menu")
logging.info("calling payment gateway")
logging.info("user subscribed - sending welcome message")

Вы сразу начинаете понимать, на каком этапе бот зависает. Не «где‑то там сломалось», а конкретно «упал при вызове платёжного шлюза».

Ошибки

Вот это конструкция, которую я использую всегда и везде. Просто запомните её:

try:
    result = some_function()
except Exception as e:
    logging.exception("error in handler")

logging.exception() сам добавляет стек вызовов в сообщение. Вы увидите не «ошибка», а точную строчку, где всё полетело, с файлом и номером строки.

Реальные кейсы с моей практики

Самый ценный блок — реальные истории, когда логи меня реально спасали.

Кейс 1: бот молчит

Пользователь пишет «/start», бот ничего не отвечает. Открываю логи:

INFO | user=123 text=/start

И дальше — пустота. Ни «sending profile menu», ни ошибок, ничего.

Вывод: обработчик команды /start либо не зарегистрирован, либо фильтр сломался, либо событие ушло куда‑то не туда. Логи сузили поиск с «где‑то сломалось» до «проблема в диспетчеризации». Это уже победа.

Кейс 2: бот падает с грохотом

Пользователь что‑то делает, и бот вылетает с ошибкой. Смотрю в логи:

ERROR | KeyError: 'user_id'
  File "handlers/order.py", line 34, in handle_order
    user_id = data['user_id']

Всё. Вопрос закрыт. В данных не было ключа user_id, а я его тупо дёрнул без проверки. Лог указал на конкретную строчку — починил за минуту.

Кейс 3: бот двойнит сообщения

Бот отправляет одно и то же сообщение дважды. Смотрю логи:

INFO | handler called for user=123
INFO | handler called for user=123

Вывод: обработчик вызывается дважды. Значит, роутер зарегистрирован два раза — например, подключил модуль два раза или middleware настроил криво.

Логи и асинхронность: ловушка для новичков

Это классика. Бот на asyncio, внутри хендлера кто‑то пишет:

time.sleep(1)

И всё. Весь event loop засыпает. Логи перестают писаться. Бот перестаёт отвечать другим пользователям.

Правильный вариант — await asyncio.sleep(1). Если вы видите в логах длинную паузу между записями и никаких объяснений — ищите блокирующий код. Он всегда найдётся, проверено.

Логи в продакшене — взрослая жизнь

В разработке вы смотрите логи в терминале и радуетесь. В продакшене этот номер не проходит.

Куда писать. Самый простой способ — в файл. Добавляем второй обработчик:

file_handler = logging.FileHandler("bot.log")
file_handler.setFormatter(logging.Formatter("%(asctime)s | %(levelname)s | %(message)s"))
logger.addHandler(file_handler)

Если у вас Docker — логи пишутся в stdout и stderr, а Docker сам разберётся, куда их направить.

Но есть одна проблема. Файл bot.log со временем разрастается до гигабайт. И вы об этом вспоминаете в самый неподходящий момент. Нужна ротация.

from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler(
    "bot.log", 
    maxBytes=10_000_000,  # 10 мегабайт
    backupCount=5
)

Теперь у вас хранится пять файлов по 10 мегабайт. Старые логи не теряются, но диск не забивается.

Как читать логи по‑человечески

Просто «открыть файл и листать» — неправильно. Нужно уметь искать, и аккуратно.

Ищите по user_id. Пришла жалоба от пользователя 12345. Открываете лог и ищете user=12345. Смотрите всю последовательность: что он нажал, что бот ответил, была ли ошибка.

Ищите по ERROR. Это все места, где бот сломался. Если ошибок много — у вас системная проблема, и пора что‑то с этим делать.

Лог — это история. Вы должны восстановить хронологию: запрос пришёл → бот начал обработку → бот вызвал внешний API → API молчит → бот упал.

Что логировать нельзя (не повторяйте мои ошибки)

Очень важный блок. Не всё, что можно вывести в лог, нужно выводить. Я наступал на эти грабли, вы не наступайте.

Токены. Никогда — слышите, никогда? — не пишите в лог bot_tokenapi_keyaccess_token. Один случайно сохранённый лог‑файл, и ваши ключи уплывают в открытый доступ.

Пароли. Даже если пользователь сам ввёл пароль в сообщение — не логируйте тело сообщения полностью. Логируйте факт отправки, но не содержимое. Правда, пожалейте людей.

Персональные данные. Телефоны, адреса, номера карт. Логи могут попасть в Sentry, в чаты поддержки, в системы сбора логов. Это уже зона ответственности и комплаенса. Один слив — и вы пишете объяснительную:)

Продвинутый уровень (когда стало тесно)

Если базового подхода уже мало, можно пойти дальше. Но это уже для тех, кому мало.

JSON‑логи. Вместо текстовой строки вы пишете JSON с полями timestampleveluser_idmessage. Это позволяет подключать централизованные системы сбора логов — ELK, Loki, которые умеют индексировать и быстро искать по любому полю. Красота, но сложновато для старта.

Correlation ID. Каждому входящему запросу назначается уникальный идентификатор, который бежит через все вызовы. В логах появляется поле request_id=abc-123. Вы можете собрать все записи по одному запросу, даже если они разбросаны по разным модулям. Выглядит как магия, но работает.

Интеграция с Sentry. Sentry автоматически собирает исключения, контекст, окружение. Вы ставите sentry_sdk.init(), и все падения бота оказываются в веб‑интерфейсе с полным стеком и контекстом. Бесплатно для небольших проектов.

Ключевая мысль, которую я хочу донести

Логи — это не «для галочки». Это не формальность и не свалка отладочного текста. Логи — это единственный инструмент, который поможет вам понять, что происходит с ботом, когда вы спите и видите десятый сон.

Когда ваш продакшен‑бот падает в два часа ночи, логи становятся единственным свидетелем происходящего. Правильные логи дают контекст. Они показывают не просто «упало», а «упало вот тут, с такими‑то данными, перед таким‑то действием».

Без логов вы слепы. С логами вы берёте файл bot.log, находите строчку с ERROR и через пару минут уже понимаете, где править код.

Настройте логи прямо сейчас. Это займёт пятнадцать минут, но сэкономит вам несколько ночей дебага.