Краткий отчёт по учебному журналу
В прошлом уроке мы нашли отдельные строки и сохранили их контекст. Теперь обобщим учебный журнал: сколько ответов относится к каждому статусу и какие пути встречаются чаще. Такой отчёт помогает выбрать направление дальнейшего исследования. Он не объясняет причину сам по себе: несколько ответов 500 показывают симптом, но не говорят, какой модуль приложения нарушил свой договор.
Продолжаем работать с fixtures/access.tsv. Здесь шесть столбцов: время, статус, метод, путь, длительность в миллисекундах и идентификатор запроса. Заголовок занимает первую строку. Разделитель — табуляция; пробел внутри значения не создаёт новый столбец. Это важная предпосылка всех следующих команд. У произвольного журнала сервера сначала потребуется выяснить собственный формат.
Поле выбираем явно
Сначала получим только второй столбец, исключив заголовок. awk позволяет обратиться к полю по номеру. Устанавливаем разделитель во входных данных, чтобы запрос не зависел от случайного количества пробелов в строке.
awk -F '\t' 'NR > 1 { print $2 }' fixtures/access.tsv
NR обозначает номер обрабатываемой записи, а $2 — второе поле. Выражение перед блоком ограничивает его применение строками после заголовка. Ожидаемый результат — один статус на строку. Это уже отличается от поиска текста 500: мы извлекаем значение именно из договорённого места, а не ищем похожие цифры во всём сообщении.
Проверьте взглядом несколько исходных строк и соответствующие значения. Если в результате появляется путь или метод, скорее всего, договор о столбцах не совпадает с входом. Увеличение числа команд в конвейере не исправляет неправильный первый шаг. Сначала нужно подтвердить структуру данных, иначе каждый следующий этап будет аккуратно обрабатывать ошибочно выбранное поле.
У реального входа также могут встретиться пустые или неполные строки. Если второй столбец отсутствует, общий подсчёт способен создать группу пустого значения. Это полезный сигнал качества данных, который нельзя молча переименовать в успешный запрос. В нашем фиксированном наборе каждая запись имеет шесть полей; при переходе к другому источнику добавьте отдельную проверку структуры и описание того, как обрабатывается неподходящая запись.
Для профиля Ubuntu синтаксис полей и разделителя объясняет справка mawk, одной из реализаций awk. Наш короткий пример использует общие возможности языка; выбор реализации всё равно стоит записать, когда сценарий получает более сложные расширения.
Порядок нужен для подсчёта повторов
uniq объединяет соседние одинаковые строки. Поэтому перед общим подсчётом отсортируем значения. Без сортировки два одинаковых статуса, разделённые другим статусом, останутся разными группами. Результат может выглядеть убедительно, но не отвечать на вопрос о суммарной частоте.
awk -F '\t' 'NR > 1 { print $2 }' fixtures/access.tsv | LC_ALL=C sort | uniq -c
Для подготовленных данных ожидаются группы 200, 201, 404 и 500. Учебная таблица содержит двенадцать запросов: четыре ответа 200, три 201, два 404 и три 500. Эти числа можно получить простым чтением входа; они не являются результатом выполненного при подготовке конвейера. Сопоставление суммы с числом записей помогает заметить потерю или случайное включение заголовка.
LC_ALL=C в этом примере задаёт предсказуемое сравнение коротких технических значений для одной команды. Это не настройка языка всей системы и не универсальное требование к пользовательскому тексту. Для имён на разных языках правила сортировки могут быть частью продукта. Наши статусы состоят из цифр, поэтому сложные языковые различия здесь не нужны.
Выборка ошибок сохраняет исходные поля
Теперь выберем строки со статусом 500. На этом шаге важно оставить все поля, чтобы после краткого отчёта можно было вернуться к конкретным запросам. В архиве есть сценарий scripts/report-status.sh, выполняющий тот же принцип для фиксированной учебной таблицы; пока разберём одну команду.
awk -F '\t' 'NR == 1 || $2 == 500' fixtures/access.tsv > evidence/server-errors.tsv
Первая часть сохраняет заголовок. Вторая выбирает нужное значение поля. Полученный файл подходит для дальнейшего табличного чтения, в отличие от результата grep -n, где к каждой строке добавляется номер. Номер полезен человеку, но изменяет формат. Поэтому обычный просмотр и машинная передача не всегда должны использовать одну и ту же форму вывода.
Путь /api/tickets в отчёте может встречаться с разными методами. Создание через POST и чтение через GET — разные операции. Если проблема касается сохранения заявки, общий подсчёт пути смешивает их. Выберите пару «метод и путь», затем отдельно рассмотрите статусы. Такое уточнение вопроса полезнее попытки сразу строить множество графиков по всем полям.
Несколько простых преобразований
cut удобно выбирает столбец, когда нужен только один кусок строки. tr преобразует символы, а sed выполняет потоковое редактирование. В нашей лаборатории покажем их на просмотре, оставив исходный журнал неизменным. Названия методов можно выбрать, отсортировать и сгруппировать точно так же, как статусы.
tail -n +2 fixtures/access.tsv | cut -f 3 | LC_ALL=C sort | uniq -c
head -n 3 fixtures/access.tsv | tr '\t' '|'
sed -n '2,5p' fixtures/access.tsv
Замена табуляции на вертикальную черту нужна только для наглядного показа разделителя. Она не превращает произвольные данные в корректный CSV и не учитывает появление самой черты внутри значений. Аналогично выбор строк со второй по пятую не является фильтром по времени. Каждый инструмент делает ровно описанное преобразование; смысл результата задаёт наш договор.
Для sed полезна справка установленного профиля Ubuntu. Здесь используем подавление обычного вывода и явную печать диапазона. Изменение файла на месте не требуется. При изучении нового выражения безопаснее сначала увидеть результат отдельным потоком, сравнить его с входом и только затем решать, нужен ли изменённый файл вообще.
Доля и её знаменатель
Три ответа 500 из двенадцати дают четверть учебных записей. Но это доля в маленьком искусственном наборе, а не показатель надёжности DeskQueue. В настоящем отчёте необходимо указать период, источник и способ отбора. Если мы заранее сохранили только подозрительные строки, доля ошибок в такой выборке не описывает весь поток запросов.
Длительность тоже требует контекста. Среднее может скрыть редкие медленные операции, а один максимум зависит от выбранного периода. В этом уроке не строим итоговую систему мониторинга. Наша задача скромнее: научиться сохранять договор данных при простых преобразованиях и не приписывать короткому отчёту больше смысла, чем у него есть.
В evidence/log-report.md запишите входной файл, число строк без заголовка, подсчёт статусов и ограничение «синтетические данные». Отдельно сформулируйте следующий вопрос: например, какие именно операции завершились статусом 500. Результат урока — понятная сводка и сохранённая выборка исходных записей. Затем перейдём от текстов к пользователям, от имени которых процессы получают доступ к этим файлам.