Для каждого IP и каждой минуты, если число событий с level=ERROR ≥ 5, нужно вывести алерт.
minute_start = timestamp - (timestamp % 60)- Окно включает секунды [minute_start, minute_start + 59] включительно.
- На вход подаётся директория с файлами (без рекурсии).
- Читать все файлы из директории.
- Кодировка: UTF-8.
- Все строки валидны по формату.
Формат строки (поля разделены пробелом, порядок полей гарантирован):
<timestamp> userId=<user> ip=<ip> level=<LEVEL> msg="<...>"
Где:
| Поле | Описание |
|---|---|
timestamp |
Целое число (Unix epoch, секунды). |
userId |
[A-Za-z0-9]+ (присутствует, но не используется в агрегации). |
ip |
IPv4 (строкой, без кавычек). |
level |
Одно из: INFO, WARN, ERROR. |
msg |
Строка в двойных кавычках, может содержать пробелы. |
- Писать строго в файл
out.txtв текущей директории. - Формат — по одной JSON-записи в строке (JSON Lines), строгий JSON (только двойные кавычки).
- Ровно один алерт на IP и минуту (если выполнено условие).
Поля объекта (рекомендуемый порядок):
{
"type": "alert",
"ip": "<ip>",
"window_start": <minute_start>,
"window_end": <minute_start + 59>,
"error_count": <количество ERROR для этого ip в этом окне, ≥ 5>
}Сортировка строк в out.txt:
- по
ip(лексикографически), - затем по
window_startпо возрастанию.
1697847301 userId=a ip=10.0.0.1 level=ERROR msg="e1"
1697847310 userId=a ip=10.0.0.1 level=ERROR msg="e2"
1697847320 userId=a ip=10.0.0.1 level=ERROR msg="e3"
1697847330 userId=a ip=10.0.0.1 level=ERROR msg="e4"
1697847340 userId=a ip=10.0.0.1 level=ERROR msg="e5"
1697847341 userId=b ip=10.0.0.1 level=ERROR msg="e6"
1697847360 userId=f ip=10.0.0.1 level=ERROR msg="e7"
Окно 1697847300..1697847359:
для IP 10.0.0.1 имеется 6 ERROR → алерт.
{"type":"alert","ip":"10.0.0.1","window_start":1697847300,"window_end":1697847359,"error_count":6}- Считаем только
level=ERROR(точное совпадение). - Если ошибок больше 5 —
error_countпоказывает фактическое число, алерт один. - Окна фиксированные по минутам (не скользящие).