Что такое stdout и stderr — и почему ошибки не попадают в твой лог-файл

Смотри, загадка. Ты запускаешь python bot.py > log.txt, чтобы весь вывод ушёл в файл. Программа падает. Ошибка красуется прямо на экране. Открываешь log.txt — а там только обычные сообщения, никакой ошибки.
Файл не сломан, и > не сломан. Просто у каждой программы не один выход, а два. Ты перенаправил только один.
Два выхода у каждой программы
Когда программа что-то печатает, она выбирает, в какую «трубу» писать:
- stdout (standard output, стандартный вывод) — обычный результат работы.
- stderr (standard error, вывод ошибок) — ошибки, предупреждения, служебные сообщения.
По умолчанию обе трубы выведены на экран терминала. Поэтому ты их не различаешь — текст просто идёт подряд.
Зачем две? Чтобы результат и проблемы не смешивались. Представь кухню: готовые блюда идут через окно раздачи, а жалобы — через отдельную дверь. Если отправить блюда на банкет, жалобы всё равно придут к тебе, а не гостям.
Кто куда пишет:
print()в Python иconsole.log()в Node — в stdout.console.error()в Node — в stderr.- Модуль
loggingв Python по умолчанию — в stderr. Да, даже обычные INFO-сообщения. - Трейсбек упавшей программы — всегда в stderr.
Как управлять трубами
У труб есть номера: stdout — это 1, stderr — 2. Отсюда весь синтаксис:
python bot.py > out.txt # только stdout в файл
python bot.py 2> errors.txt # только stderr в файл
python bot.py > all.txt 2>&1 # обе трубы в один файл
python bot.py 2>/dev/null # ошибки — в никуда
2>&1 читается как «отправь вторую трубу туда же, куда сейчас идёт первая».
И вот грабли, на которые наступают все. Порядок важен:
python bot.py > all.txt 2>&1 # ✓ обе трубы в файле
python bot.py 2>&1 > all.txt # ✗ ошибки всё равно на экране
Перенаправления выполняются слева направо. Во втором варианте 2>&1 сработал первым — когда stdout ещё смотрел на экран. Ошибки «прилипли» к экрану. Потом stdout ушёл в файл, а stderr остался. Запомни: сначала файл, потом 2>&1.
А иногда трубы полезно, наоборот, развести по разным файлам:
npm run build > build.log 2> errors.log
Сборка напечатала тысячу строк прогресса, а ошибок три. Открываешь errors.log — и сразу видишь только их, без прокрутки.
Та же логика и с трубой |: она передаёт дальше только stdout. Поэтому npm run build | grep error может ничего не найти — ошибки шли мимо, в stderr.
Почему логи Python в Docker приходят с опозданием
Вторая загадка. Бот в Docker работает, но docker logs пустой. А через пару минут вываливается сразу пачка сообщений.
Дело в буфере. Когда stdout смотрит в терминал, Python отправляет каждую строку сразу. Когда stdout уходит в файл или трубу — как в Docker — Python копит текст и отправляет порциями. Ради скорости.
А stderr не копится никогда. Ошибки приходят мгновенно, а обычные print застряли в буфере. Отсюда странные логи, где ошибка стоит раньше событий, которые к ней привели.
Чинится одним из трёх способов:
python -u bot.py # запуск без буфера
ENV PYTHONUNBUFFERED=1 # в Dockerfile — для всего контейнера
print("старт", flush=True) # для одной строки
Строку с PYTHONUNBUFFERED=1 ты увидишь почти в каждом Dockerfile для Python. Теперь ты знаешь зачем.
Как это помогает в работе с ИИ
Когда ИИ-агент запускает команду, он видит обе трубы и код выхода. Но если ты сам копируешь ему вывод, частая ошибка — скопировать только «чистую» часть. Сохраняй всё: команда > out.txt 2>&1, и отдавай файл целиком. Самое ценное для отладки обычно в stderr: путь к файлу, номер строки, имя упавшей функции. Без этого ИИ гадает, а с этим — чинит с первого раза.
А если нужны постоянные логи на сервере — это уже следующий уровень, о нём в статье что такое логи.
Ошибка в stderr значит, что программа упала?
Нет. В stderr пишут и предупреждения, и прогресс — например, npm и git выводят туда много служебного. Упала ли программа, говорит только код выхода.
Есть ли stdout и stderr на Windows?
Да. В PowerShell и cmd работают те же >, 2> и 2>&1. Только вместо /dev/null пишут NUL в cmd или $null в PowerShell.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





