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

Команды, лайфхаки и список утилит — под катом. Предупрежу, в статье МНОГО БУКВ, поэтому можно сразу перейти к Linux, Windows или к инструментам (они в самом конце). 

Что такое логи

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

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

Если пользователь видит 502, разумнее начать с nginx или приложения, а не с полного системного журнала за сутки. Если не работает SSH-вход, первым делом пригодятся auth.log, secure или события безопасности в Windows. Если служба внезапно умерла, смотреть придётся и журнал приложения, и менеджер служб, и системные события рядом с падением. 

Теперь к уровням важности, потому что без них лог быстро начинает напоминать стену текста из «Матрицы». У сообщений есть уровни важности: 

  • INFO описывает штатную работу.

  • DEBUG помогает разработчику увидеть детали выполнения.

  • WARN предупреждает о возможной проблеме.

  • ERROR фиксирует ошибку.

  • FATAL и CRITICAL указывают на критическое состояние или ошибку, которая серьёзно нарушает работу системы или компонента.

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

Отдельная радость разработчиков и периодическая боль админов — stack trace, цепочка вызовов, по которой приложение дошло до сбоя. Она показывает место, где проблема проявилась, но причина может быть в другом слое, поэтому тут аккуратнее. 

С чего начинать разбор

Когда всё уже горит, первое, что все ищут — это error. Иногда это помогает, но чаще заводит в дебри. Я рекомендую начинать с рамки поиска, например, зафиксировать:

  • когда началась деградация,

  • где она стала заметна,

  • какой компонент ближе всего к симптому,

  • какие журналы относятся именно к этой цепочке. 

Если мониторинг показывает рост 5xx с 14:32, нет смысла читать весь access.log за сутки. Берите интервал вокруг 14:32, смотрите входной трафик, ошибки приложения, состояние сервиса и системные события рядом с этим временем.

Лучше идти по схеме: симптом, ближайший к нему компонент, зависимости и системный слой. Например, при ошибках на сайте можно идти от nginx к приложению, затем к базе, очереди, DNS, файловой системе и ядру. 

Как собрать одну историю из нескольких источников

О том, как читать логи, когда их много, разберу по системам Linux и Windows, а также отдельно расскажу пару лайфхаков для контейнерных сред. 

Linux 

Начнём с Linux, потому что именно там чаще всего приходится работать по SSH. Логи чаще всего лежат в /var/log/, но конкретные пути зависят от дистрибутива и сервиса. 

В Debian и Ubuntu системные сообщения обычно можно найти в /var/log/syslog, а авторизацию — в /var/log/auth.log. В RHEL, CentOS, AlmaLinux и Rocky Linux чаще встречаются /var/log/messages и /var/log/secure. 

Логи nginx обычно лежат в /var/log/nginx/, Apache — в /var/log/apache2/ или /var/log/httpd/, PostgreSQL и MySQL могут писать как в свои каталоги, так и в journald, если так настроен сервис.

Если в системе используется systemd, я бы начинал с journalctl, потому что он уже умеет фильтровать записи по сервису, времени, PID, загрузке и уровню важности, а не заставляет вас руками вылавливать нужную строку из общего болота. Например, чтобы посмотреть последние 200 строк конкретного сервиса, замените myapp.service на имя своего юнита:

journalctl -u myapp.service -n 200 --no-pager

Если сервис называется nginx, команда будет такой:

journalctl -u nginx -n 200 --no-pager

Ключ -n 200 показывает последние 200 записей. Если сервис пишет редко, хватит -n 50, если он шумный, ставьте -n 1000. В свою очередь, --no-pager отключает постраничный просмотр, чтобы вывод сразу попал в терминал или его можно было передать дальше.

Если известен интервал инцидента, лучше сразу ограничить время. Например, деградация началась 14 марта 2025 года около 21:00, а к 21:30 сервис уже восстановился:

journalctl -u myapp.service --since "2025-03-14 21:00" --until "2025-03-14 21:30" --no-pager

Для живого наблюдения за сервисом используем -f, как в tail -f:

journalctl -u myapp.service -f

Если нужны только предупреждения и ошибки, добавляем фильтр по приоритету:

journalctl -u myapp.service -p warning..alert --since "1 hour ago" --no-pager

Здесь warning..alert отсекает обычные информационные сообщения — это удобно, когда сервис пишет много INFO. Но помните, иногда причина прячется именно в нормальной на вид строке перед ошибкой.

Если сервис падал после перезагрузки или проблема могла быть в предыдущем boot, полезно сравнить текущую и прошлую загрузку:

journalctl -b -u myapp.service --no-pager

journalctl -b -1 -u myapp.service --no-pager

Тут -b показывает текущую загрузку, -b -1 — предыдущую. Это помогает, когда после ребута симптом исчез, а причина осталась в прошлом журнале.

Сообщения ядра смотрим отдельно. Это нужно при подозрении на OOM Killer, диск, файловую систему, сетевой интерфейс или драйвер:

journalctl -k --since "1 hour ago" --no-pager

Быстрая фильтрация по частым словам для таких случаев:

journalctl -k --since "1 hour ago" | grep -Ei 'oom|killed process|segfault|ext4|xfs|nvme|i/o error|link is down|reset'

Если видите Killed process, рядом обычно будет процесс, который прибил OOM Killer. Если появляются I/O error, nvme reset или ошибки файловой системы, проблема уже может быть ниже приложения.

Когда journald закончился и перед вами обычный файл, начинается старая школа. С обычными файлами логов помогает поиск с контекстом. Не просто нашли строку, а сразу увидели, что было до и после неё:

grep -n -A20 -B10 'timeout' /var/log/myapp/app.log

timeout замените на IP, логин, request ID, код ошибки или фрагмент сообщения. -A20 показывает 20 строк после совпадения, -B10 — 10 строк до него, -n добавляет номера строк. Если событие короткое, хватит -A5 -B5; если нужно увидеть длинную цепочку, ставьте -A50 -B20.

Для поиска без учёта регистра добавьте -i:

grep -ni -A10 -B10 'exception' /var/log/myapp/app.log

Если нужно пройтись по каталогу с логами, а не по одному файлу:

grep -Rni --include='*.log' 'timeout' /var/log/myapp/

--include='*.log' не даёт grep лезть во временные файлы и всё, что случайно лежит рядом. 

Если логи уже сжаты после ротации, используем zgrep:

zgrep -ni 'timeout' /var/log/myapp/app.log*.gz

Если формат времени в логе понятный, не читайте сутки целиком. Например, записи начинаются с 2025-03-14 21:05:..., и нужен весь час 21:

grep '^2025-03-14 21:' /var/log/myapp/app.log

Если нужен диапазон минут, например с 21:10 до 21:19:

grep '^2025-03-14 21:1[0-9]:' /var/log/myapp/app.log

Для текущего файла используем tail. Если хотите увидеть последние 500 строк и продолжить следить за новыми, число можно менять под шумность сервиса:

tail -n 500 -f /var/log/myapp/app.log

Если файл ротируется, лучше -F, потому что он продолжит следить за новым файлом после переименования старого:

tail -n 500 -F /var/log/nginx/error.log

Access-логи особенно коварны, ведь они выглядят как бесконечная очередь одинаковых строк, но в агрегатах полезны. Их лучше сразу превращать в счётчики. Например, смотреть на самые частые IP в nginx:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -20

head -20 показывает первые 20 результатов. Если нужен более широкий список, меняете на head -50. 

Если у вас нестандартный формат access-лога, сначала посмотрите пару строк:

head -3 /var/log/nginx/access.log

Если в log_format nginx последним полем пишется $request_time, самые медленные запросы можно посмотреть так:

awk '{print $NF, $7, $9}' /var/log/nginx/access.log | sort -nr | head -20

Если время запроса у вас в другом месте, сначала проверьте формат логирования:

grep -R "log_format" /etc/nginx/nginx.conf /etc/nginx/conf.d/

С auth-логами логика та же. Не читайте всё подряд, а сразу собирайте выборки. Например, в Debian и Ubuntu неудачные SSH-входы можно посмотреть через:

grep 'Failed password' /var/log/auth.log | tail -50

А в RHEL-подобных системах через:

grep 'Failed password' /var/log/secure | tail -50

Из лайфхаков для Linux самый полезный — всегда искать request ID, trace ID или correlation ID, если они есть. По ним проще собрать путь одного запроса через nginx, приложение, очередь и воркер:

grep -Rni 'request_id=abc123' /var/log/myapp/

Если идентификатор похож на UUID, можно сначала посмотреть, какие ID повторяются чаще всего:

grep -oE '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' /var/log/myapp/app.log | sort | uniq -c | sort -nr | head -20

После этого берём подозрительный ID и смотрим его с контекстом:

grep -n -A30 -B10 'abc123' /var/log/myapp/app.log

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

Windows

Если в Linux «всё есть файл» (и, как правило, текстовый), то архитектура логирования в Microsoft исторически пошла по пути строгой структуризации и бинарных форматов. Переход к службе Event Tracing for Windows (ETW) и XML-схемам сделал невозможным простой парсинг логов с помощью grep или Notepad, вынуждая глубоко изучать PowerShell и архитектуру журналов.

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

  • Классические системные журналы (System, Application, Security) и сотни специализированных логов сервисов складируются в директории C:\Windows\System32\winevt\Logs\ в формате .evtx.

  • Логи веб-сервера IIS сохраняются в %SystemDrive%\inetpub\logs\LogFiles\ или C:\Windows\System32\LogFiles\. Директории внутри именуются по принципу W3SVC1, W3SVC2, где цифра соответствует внутреннему идентификатору сайта в консоли IIS.

  • Windows Update (ETW) начиная с Windows 10 прекратила запись в простой текстовый файл C:\Windows\WindowsUpdate.log. Теперь телеметрия непрерывно сбрасывается в бинарные .etl файлы, спрятанные в C:\Windows\logs\WindowsUpdate.

Главное правило то же, что в Linux — сначала ограничиваем выборку, потом читаем.

Основные журналы такие: System для системных событий и служб, Application для приложений, Security для аудита входов и действий безопасности, а также отдельные журналы приложений и ролей Windows Server. Если падает служба, начинайте с System и Service Control Manager. Если падает приложение, смотрите Application. Если вопрос в логине, правах или подозрительной активности, нужен Security, но для него часто потребуются права администратора.

Также важно, что долгие годы основным инструментом извлечения событий в PowerShell оставался командлет Get-EventLog. Однако его архитектура безнадёжно устарела — сейчас он работает только с устаревшими классическими журналами, использует нестабильные (deprecated) API Windows и, что самое критичное, абсолютно неэффективен при фильтрации данных.

Microsoft рекомендует использовать Get-WinEvent — фильтрация тут происходит на стороне самой службы Eventlog. Для достижения максимальной скорости Get-WinEvent предлагает два механизма фильтрации: FilterHashTable и FilterXML.

Дальше по командам. Системные события за последние 30 минут смотрите через:

Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=(Get-Date).AddMinutes(-30)}

Если нужно не 30 минут, а два часа, меняете AddMinutes(-30) на AddHours(-2):

Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=(Get-Date).AddHours(-2)}

Ошибки из журнала приложений за последние два часа:

Get-WinEvent -FilterHashtable @{LogName='Application'; Level=2; StartTime=(Get-Date).AddHours(-2)}

Level=2 означает ошибки, Level=3 — предупреждения, Level=4 — информационные события.

Если нужны ошибки и предупреждения вместе, можно отфильтровать короткую выборку так:

Get-WinEvent -FilterHashtable @{LogName='Application'; StartTime=(Get-Date).AddHours(-2)} |

  Where-Object {$_.LevelDisplayName -in 'Error','Warning'}

Конкретный ID события, например, падение приложения с Event ID 1000 смотрите через:

Get-WinEvent -FilterHashtable @{LogName='Application'; ID=1000; StartTime=(Get-Date).AddHours(-2)}

А события Service Control Manager, которые помогают понять, когда служба стартовала, упала или была остановлена через:

Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Service Control Manager'; StartTime=(Get-Date).AddHours(-2)}

Однако чтобы вывод был читаемым, оставляем только время, ID, источник, уровень и сообщение:

Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=(Get-Date).AddMinutes(-30)} |

  Select-Object TimeCreated, Id, ProviderName, LevelDisplayName, Message |

  Format-List

Для журнала безопасности можно посмотреть неудачные входы за последний час. Например, Event ID 4625 означает failed logon:

Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4625; StartTime=(Get-Date).AddHours(-1)} |

  Select-Object TimeCreated, Id, ProviderName, Message |

  Format-List

Для текстовых логов PowerShell работает почти как tail:

Get-Content .\app.log -Tail 200 -Wait

-Tail 200 показывает последние 200 строк. Если нужен короткий хвост, ставьте 50; если лог шумный и нужно захватить момент перед ошибкой, ставьте 1000. -Wait продолжает ждать новые строки.

Также можно поискать по текстовому логу:

Select-String -Path .\app.log -Pattern 'timeout|exception|failed'

Или по каталогу:

Get-ChildItem C:\Logs -Recurse -Filter *.log |

  Select-String -Pattern 'timeout|exception|failed'

Главный лайфхак для Windows — не открывайте огромный лог блокнотом и не выгружайте весь EventLog без фильтра. Для EventLog используйте FilterHashtable, потому что фильтрация эффективнее.

Важно! Все команды в статье охватить практически НЕРЕАЛЬНО, поэтому, если вы новичок и обучаетесь или у вас прямо сейчас упала система и вы судорожно ищете выход в этой статье — я извиняюсь и рекомендую поискать ответ в обучалках, книгах или поисковике/чат-боте. Я писал материал лишь для того, чтобы напомнить про основы работы с большим числом логов. 

Что реально экономит время при разборе

Время экономят привычки. 

1. Ограничивайте выборку до чтения. В Linux это journalctl --since, --until, -u, -p, _PID. В Windows — Get-WinEvent -FilterHashtable. Чем точнее первый срез, тем меньше мусора придётся держать в голове.

2. Считайте повторы. Один error может быть фоном, а тысяча одинаковых timeout за пять минут уже похожа на симптом. Поэтому sort | uniq -c | sort -nr часто полезнее, чем чтение файла сверху вниз.

3. Смотрите контекст. Команды без -A, -B, -C часто дают слишком мало, ведь логах важна не только строка с ошибкой, но и то, что случилось перед ней. Например, новый деплой, переподключение к базе, сброс соединения, смена конфигурации или рестарт воркера.

4. Проверяйте ротацию и старые экземпляры. В Linux ошибка могла уехать в .gz, а в Windows — быть в другом журнале.

5. Сохраняйте ход расследования. Когда логов много, ваша память начинает дорисовывать удобную версию событий. Запишите время первого симптома, команды, которые уже запускали, подозрительные сообщения и гипотезы, которые не подтвердились. Через час это избавит от повторной проверки одного и того же.

И занудная, но важная 6 привычка — добавлять в приложения нормальные поля логирования. Timestamp в едином формате, уровень, сервис, instance, request ID, user ID без персональных данных, endpoint, duration, статус ответа и trace ID экономят больше времени, чем любой красивый просмотрщик. 

Топ инструментов для чтения и анализа логов

Однако для расшифровки сложных и объёмных записей пользуйтесь готовыми и доступными инструментами. Например, бесплатными локальными утилитами: 

  • lnav — консольный лог-вьювер. Он одновременно открывает несколько логов, читает архивы, распознаёт форматы, собирает временную линию и позволяет делать SQL-запросы по журналам.

  • ripgrep — быстрый рекурсивный поиск по файлам. Работает на Linux, macOS и Windows, удобен для больших каталогов логов и исходников.

  • jq — утилита для работы с JSON. Особенно полезна для контейнеров и современных приложений, которые пишут структурированные JSON-логи.

  • Klogg — графический просмотрщик больших лог-файлов. Подходит для гигабайтных файлов, которые нельзя нормально открыть обычным редактором.

  • LogExpert — Windows-утилита для просмотра логов. Умеет tail, фильтры, подсветку, вкладки и плагины. Удобна для прикладных логов в оконном интерфейсе.

  • Log Parser 2.2 — вторая Windows-утилита с SQL-подобными запросами. Полезна для IIS, Event Log, CSV, XML и текстовых журналов, особенно в старой Windows-инфраструктуре.

С централизованным сбором помогут уже более серьёзные инструменты: 

  • Grafana Loki — система хранения и поиска логов. Self-hosted версия бесплатная, а в Grafana Cloud есть бесплатный уровень и платные тарифы по объёму. Хорошо подходит для Kubernetes и микросервисов, потому что активно использует метки и не индексирует весь текст как классические полнотекстовые системы.

  • SigNoz — платформа наблюдаемости для логов, метрик и трассировок. Self-hosted версия бесплатная, облачные тарифы платные. Удобна там, где используется OpenTelemetry и нужно связать лог с трассировкой запроса.

  • Elastic Stack / ELK — стек для сбора, хранения и поиска логов на базе Elasticsearch, Logstash или Beats и Kibana. Есть бесплатные возможности в self-managed варианте. Силён в полнотекстовом поиске, аналитике и больших неструктурированных массивах.

  • Graylog — платформа централизованного управления логами. Подходит для инфраструктурных журналов, сетевых устройств, приложений, алертов и потоков событий.

  • Splunk — коммерческая платформа для централизованного сбора и поиска событий. Цена зависит от объёма данных и выбранной редакции. Сильна поисковым языком, безопасностью, аудитом и расследованием сложных инцидентов.

Вместо вывода

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

© 2026 ООО «МТ ФИНАНС»

Комментарии (2)


  1. akod67
    28.04.2026 14:03

    traceid, LLM, не?


  1. gerbert_MX
    28.04.2026 14:03

    начнем с того с логированием как и с веб-программированием может показаться что какие-то фундаментальные знания не нужны

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

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

    Лично для меня Grafana Loki возглавляет список инструментов. есть куча готовых инструментов для выгрузки в локи и его можно запускать локально в контейнере что бы удобно поработать с логами без необходимости держать постоянно запущенный.

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