0Pricing
DevOps Bootcamp · Урок

Вычисление показателей и гистограмм из потоков журналов

Агрегируйте частоту запросов, перцентили и отчёты топ-N непосредственно из потоковых данных журналов

«Вычисление показателей и гистограмм из потоков журналов» — бесплатный урок DevOps Bootcamp на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения DevOps Bootcamp, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс DevOps Bootcamp содержит 4 уроков всего.

Зачем вычислять метрики по необработанным журналам?

Рабочие системы создают тысячи строк журнала в секунду. Вместо отправки необработанных журналов на дорогостоящие аналитические платформы можно вычислять частоту запросов, процентили и отчёты top-N непосредственно в оболочке — почти без затрат.

  • Частота запросов: сколько запросов в секунду или минуту обрабатывает служба?
  • Процентили задержки: каково время ответа для p50/p95/p99?
  • Отчёты top-N: какие конечные точки, IP или коды ошибок встречаются чаще всего?

Инструменты оболочки, такие как awk, sort, uniq и bc, образуют мощный комбинируемый конвейер, который позволяет отвечать на эти вопросы по потоку журнала в реальном времени или по историческому файлу, не покидая терминал.

Структура обычного журнала доступа

Большинство веб-серверов записывают журналы в комбинированном формате журнала. Понимание его полей — основа любого конвейера вычисления метрик:

127.0.0.1 - frank [10/Oct/2024:13:55:36 -0700] "GET /api/users HTTP/1.1" 200 2326 0.042
  • Поле 1: IP клиента
  • Поле 4 (в скобках): метка времени
  • Поле 7 (в кавычках): метод HTTP и путь
  • Поле 9: код состояния
  • Поле 10: количество байт ответа
  • Поле 11: время ответа в секундах (пользовательское поле, присутствует не всегда)

Используйте awk, чтобы обращаться к полям по позиции ($1, $9 и т. д.). Поля в кавычках считаются одним токеном только при аккуратном разделении: заключите строку журнала в awk -F'"' или используйте несколько проходов.

Подсчёт частоты запросов в минуту

Чтобы вычислить количество запросов в минуту, извлеките из каждой метки времени часть, соответствующую минуте, и подсчитайте вхождения. Шаблон [day/Mon/year:HH:MM задаёт корзину часа и минуты.

Приведённый ниже конвейер читает access.log и выводит таблицу минута → количество запросов:

#!/usr/bin/env bash
# Requests per minute from an nginx/apache access log
# Usage: bash req_per_min.sh access.log

LOG="${1:-access.log}"

awk '{
    # Extract [day/Mon/year:HH:MM from field 4
    match($0, /\[([^:]+:[0-9]+:[0-9]+)/, arr)
    minute = arr[1]
    if (minute != "") count[minute]++
} END {
    for (m in count) print count[m], m
}' "$LOG" | sort -k2

Частота по скользящему окну в потоке реального времени

Для отслеживания потока в реальном времени требуется скользящее окно. Используйте tail -f, передавая его вывод в awk, который сбрасывает счётчик каждые N секунд по системным часам (systime()).

Этот пример выводит строку с частотой каждые 10 секунд:

#!/usr/bin/env bash
# Live request rate — prints lines/10s from a tailed log
# Usage: bash live_rate.sh /var/log/nginx/access.log

LOG="${1:-/var/log/nginx/access.log}"
WINDOW=10

tail -f "$LOG" | awk -v win="$WINDOW" '
BEGIN { start = systime(); count = 0 }
{
    count++
    now = systime()
    if (now - start >= win) {
        printf "[%s] %d req/%ds (%.1f req/s)\n",
               strftime("%H:%M:%S", now), count, win, count/win
        count = 0
        start = now
    }
}'

Извлечение значений задержки для вычисления процентилей

Для вычисления процентилей необходимо отсортировать все наблюдаемые значения задержки. Стандартный подход:

  1. извлечь столбец задержки в обычный список чисел;
  2. отсортировать числовые значения;
  3. выбрать значение с нужным рангом, используя подсчёт строк.

Приведённый ниже сценарий извлекает поле 11 (время ответа в секундах) и сохраняет его во временный файл для вычисления процентилей на следующем шаге:

#!/usr/bin/env bash
# Extract latency column from access log (field 11)
# Assumes last field on each line is response time in seconds

LOG="${1:-access.log}"
TMP=$(mktemp /tmp/latency_XXXXXX.txt)

awk '{ if ($NF ~ /^[0-9]+\.?[0-9]*$/) print $NF }' "$LOG" \
    | sort -n > "$TMP"

echo "Extracted $(wc -l < "$TMP") latency samples -> $TMP"
echo "$TMP"   # callers can read this file

Вычисление p50, p95 и p99 с помощью awk

После сортировки значений задержки выбор процентиля сводится к арифметике: p-й процентиль находится в строке ceil(p/100 * N). Обычный awk может выполнить это за один проход после загрузки отсортированного файла в массив:

#!/usr/bin/env bash
# Compute p50 / p95 / p99 from a sorted latency file
# Usage: bash percentiles.sh latency_sorted.txt

# Demo: generate 1000 random latencies if no file given
if [[ $# -eq 0 ]]; then
    SORTED=$(mktemp)
    for i in $(seq 1 1000); do
        awk 'BEGIN { srand(); printf "%.4f\n", 0.001 + rand()*0.999 }'
    done | sort -n > "$SORTED"
else
    SORTED="$1"
fi

awk '
{ values[NR] = $1 }
END {
    n = NR
    if (n == 0) { print "No data"; exit }
    p50  = values[int(n * 0.50 + 0.9999)]
    p95  = values[int(n * 0.95 + 0.9999)]
    p99  = values[int(n * 0.99 + 0.9999)]
    printf "p50  = %.4fs\np95  = %.4fs\np99  = %.4fs\nN    = %d\n",
           p50, p95, p99, n
}' "$SORTED"

Создание отчёта о конечных точках top-N

Отчёт top-N отвечает на вопрос: «какие пути запрашиваются чаще всего?» Классический идиоматичный конвейер оболочки:

  • awk выводит интересующее поле (например, путь URL);
  • sort группирует одинаковые значения;
  • uniq -c подсчитывает идущие подряд дубликаты;
  • sort -rn ранжирует по убыванию количества;
  • head -n N выбирает первые N результатов.
#!/usr/bin/env bash
# Top-10 most requested URL paths from access log
# Usage: bash top_endpoints.sh access.log [N]

LOG="${1:-access.log}"
N="${2:-10}"

echo "=== Top $N endpoints ==="
awk -F'"' '{ print $2 }' "$LOG" \
    | awk '{ print $2 }' \
    | sort \
    | uniq -c \
    | sort -rn \
    | head -n "$N" \
    | awk '{ printf "%6d  %s\n", $1, $2 }'

Top-N по коду состояния: быстрый поиск ошибок

Коды состояния HTTP показывают состояние службы. Группировка строк журнала по коду состояния и их подсчёт позволяют понять, являются ли ошибки редкими или системными.

Приведённый ниже сценарий формирует разбивку по всем корзинам 2xx/3xx/4xx/5xx:

#!/usr/bin/env bash
# Status code frequency breakdown
# Usage: bash status_breakdown.sh access.log

LOG="${1:-access.log}"

echo "=== HTTP Status Code Distribution ==="
awk '{ print $9 }' "$LOG" \
    | grep -E '^[0-9]{3}$' \
    | sort \
    | uniq -c \
    | sort -rn \
    | awk '{ printf "%6d  %s\n", $1, $2 }'

echo
echo "=== 5xx Error Spike Check ==="
awk '$9 ~ /^5/ { print $9, $7 }' "$LOG" \
    | sort | uniq -c | sort -rn | head -20

Гистограммы ASCII с помощью awk

Текстовая гистограмма позволяет мгновенно оценить распределение задержки в терминале или журнале CI. Подход таков:

  1. поместить каждое значение задержки в интервал (например, 0–50 мс, 50–100 мс, …);
  2. подсчитать наблюдения в каждом интервале;
  3. вывести строку из символов #, масштабированную относительно максимального количества.

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

#!/usr/bin/env bash
# ASCII latency histogram from a list of latency values in seconds
# Demo: generates synthetic data if no input file is provided

if [[ $# -eq 0 ]]; then
    # Generate 500 synthetic latencies (ms converted to s)
    python3 -c "
import random, math
for _ in range(500):
    # bimodal: fast cluster ~50ms, slow cluster ~300ms
    if random.random() < 0.75:
        v = max(1, random.gauss(50, 15))
    else:
        v = max(1, random.gauss(300, 80))
    print(f'{v/1000:.4f}')
" | sort -n | awk '
{ values[NR] = $1 * 1000 }  # convert to ms
END {
    buckets = 10; maxVal = 500
    step = maxVal / buckets
    for (i = 0; i < buckets; i++) hist[i] = 0
    for (i = 1; i <= NR; i++) {
        b = int(values[i] / step)
        if (b >= buckets) b = buckets - 1
        hist[b]++
    }
    maxCount = 0
    for (i = 0; i < buckets; i++) if (hist[i] > maxCount) maxCount = hist[i]
    print "Latency (ms)   Count   Distribution"
    print "---------------------------------------"
    for (i = 0; i < buckets; i++) {
        lo = i * step; hi = lo + step
        barLen = int(hist[i] / maxCount * 40)
        bar = ""
        for (j = 0; j < barLen; j++) bar = bar "#"
        printf "%4d-%4dms  %5d  %s\n", lo, hi, hist[i], bar
    }
}'
else
    echo "Usage: pipe a sorted latency file (in seconds) to this pattern"
fi

Объединение метрик: сводный отчёт за один запуск

В эксплуатационных инструкциях часто требуется одна команда, выводящая все основные метрики одновременно: частоту, процентили задержки, популярные конечные точки и частоту ошибок. Все изученные приёмы можно объединить в один сценарий, который сможет вызвать человек или система оповещения.

#!/usr/bin/env bash
# One-shot log summary report
# Usage: bash log_summary.sh access.log

LOG="${1:-access.log}"
[[ -f "$LOG" ]] || { echo "File not found: $LOG"; exit 1; }

TOTAL=$(wc -l < "$LOG")
ERRORS=$(awk '$9 ~ /^[45]/' "$LOG" | wc -l)
ERR_RATE=$(awk "BEGIN { printf \"%.1f\", ($ERRORS / ($TOTAL || 1)) * 100 }")

echo "====================================="
echo " Log Summary: $LOG"
echo "====================================="
printf " Total requests : %d\n" "$TOTAL"
printf " 4xx/5xx errors : %d (%.1f%%)\n" "$ERRORS" "$ERR_RATE"

echo
echo "--- Top 5 Endpoints ---"
awk -F'"' '{ print $2 }' "$LOG" | awk '{ print $2 }' \
    | sort | uniq -c | sort -rn | head -5 \
    | awk '{ printf "  %6d  %s\n", $1, $2 }'

echo
echo "--- Latency Percentiles ---"
awk '{ if ($NF ~ /^[0-9]+\.?[0-9]*$/) print $NF * 1000 }' "$LOG" \
    | sort -n \
    | awk '
{ v[NR]=$1 }
END {
  if (NR==0) { print "  No latency data"; exit }
  printf "  p50 = %.1fms\n", v[int(NR*0.50+0.9999)]
  printf "  p95 = %.1fms\n", v[int(NR*0.95+0.9999)]
  printf "  p99 = %.1fms\n", v[int(NR*0.99+0.9999)]
}'

Потоковая передача метрик через именованные каналы и tee

В конвейерах наблюдаемости часто требуется разветвить поток журнала: записывать необработанные строки на диск и одновременно вычислять метрики. tee с именованным каналом (mkfifo) позволяет сделать это без буферизации всего потока в памяти.

  • mkfifo /tmp/log_pipe — создать именованный канал
  • tee /tmp/log_pipe | metric_consumer & — направить одну ветвь потребителю метрик
  • Другая ветвь записывает данные в файл архива

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

#!/usr/bin/env bash
# Fan-out: write to archive AND count errors in real time
# Run: bash fanout_pipeline.sh /var/log/nginx/access.log

LOG="${1:-/var/log/nginx/access.log}"
ARCHIVE="/tmp/access_archive.log"
PIPE="/tmp/log_metrics_pipe"

# Clean up on exit
trap 'rm -f "$PIPE"' EXIT

mkfifo "$PIPE"

# Branch 1: count 5xx errors per minute from the pipe
awk '$9 ~ /^5/ {
    match($0, /\[([^:]+:[0-9]+:[0-9]+)/, arr)
    errors[arr[1]]++
} END {
    for (m in errors) printf "5xx errors at %s: %d\n", m, errors[m]
}' "$PIPE" &

# Branch 2: archive to disk + feed Branch 1 via pipe
tail -f "$LOG" | tee "$PIPE" >> "$ARCHIVE"

Какая техника awk правильно вычисляет 95-й процентиль из отсортированного массива из N значений задержки?

Вы загрузили N отсортированных значений задержки в массив awk v[1..N]. Какое выражение правильно извлекает 95-й процентиль?

Итоги урока: метрики и гистограммы из потоков журналов

В этом уроке Вы построили полноценный конвейер сбора метрик непосредственно в Bash:

  • Частота запросов: awk извлекает минутный интервал из временных меток и подсчитывает вхождения; сочетание tail -f и systime() обеспечивает частоту в реальном скользящем окне.
  • Процентили задержки: извлеките столбец задержки, выполните sort -n, а затем выберите строку с индексом ceil(p/100 * N), используя в awk выражение int(N * p + 0.9999).
  • Отчёты Top-N: классический конвейер awk | sort | uniq -c | sort -rn | head -N работает с любым категориальным полем (путь, IP, код состояния).
  • Гистограммы ASCII: распределите значения по интервалам, подсчитайте количество значений в каждом интервале и масштабируйте длину столбца относительно максимального количества для быстрой оценки распределения.
  • Разветвление с именованными каналами: сочетание mkfifo и tee позволяет одновременно архивировать исходные журналы и передавать их потребителям метрик, не загружая поток в память.

Эти комбинируемые примитивы устраняют необходимость во внешних инструментах во время инцидентов и образуют основу лёгких скриптов наблюдаемости, работающих везде, где работает Bash.

Часто задаваемые вопросы

Урок «Вычисление показателей и гистограмм из потоков журналов» бесплатный?

Да — полный текст урока «Вычисление показателей и гистограмм из потоков журналов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс DevOps Bootcamp, подпишись на CoddyKit PRO. Курс DevOps Bootcamp содержит 4 уроков всего.

Чему я научусь в уроке «Вычисление показателей и гистограмм из потоков журналов»?

Агрегируйте частоту запросов, перцентили и отчёты топ-N непосредственно из потоковых данных журналов Ты практикуешь DevOps Bootcamp с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать DevOps Bootcamp?

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

Сколько времени занимает урок «Вычисление показателей и гистограмм из потоков журналов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке DevOps Bootcamp?

Да. Каждый урок DevOps Bootcamp включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Масштабный разбор веб-журналов и журналов приложений
  2. Отслеживание журналов в реальном времени и потоковые оповещения
  3. Запросы к journald с journalctl в скриптах
  4. Вычисление показателей и гистограмм из потоков журналов
← Назад к DevOps Bootcamp