Налаштування парсингу та збагачення логів (Logstash/Fluentd)

Коли сервіси записують події в різних форматах, команда витрачає години на пошук причини збою. Ми налаштовуємо розбір і збагачення логів під ключ: приводимо дані до єдиного вигляду та додаємо до них контекст. Час розслідування скорочується в рази, а черговий бачить повну картину.
Часті запитання

Парсинг логів: де ламається розбір і що втрачає команда

Конвеєр збору логів виглядає рівно до того моменту, коли черговий сервіс змінює формат виводу.

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

Ламається зазвичай у трьох місцях. Багаторядкові стеки виключень розпадаються на десятки окремих рядків, бо агент не знає, де запис закінчується.

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

Далі вступає ціна. Биті рядки логів займають обсяг, але не відповідають на запитання: за ними не можна відфільтрувати за кодом відповіді, тривалістю чи ідентифікатором запиту — лише шукати підрядок вручну.

Структурування логів, якого не сталося, обертається втратою контексту інциденту: записи з кількох сервісів доводиться зводити за часом і сподіватися, що мітки збігаються. Налагодження маски займає хвилини, а розбір аварії без структури — години.

Нижче розбираємо, як це закривається: де лагодити розбір, як утримувати багаторядкові записи цілком і які перевірки ставити на сам конвеєр, щоб нерозібрана подія була видна відразу, а не в момент відмови.

Ефект від розбору та збагачення: що змінюється в роботі

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

Той самий збій доводиться шукати кількома запитами, а частина рядків узагалі не розпізнається парсером і осідає мертвим вантажем — за ними потім не відновити хронологію.

Нормалізація полів зводить різнорідні джерела до єдиної схеми подій: у запису з'являються однакові мітки сервісу, середовища, рівня та ідентифікатора запиту.

Після цього пошук іде одним запитом по всіх джерелах, а події різних сервісів з'єднуються за спільною ознакою — ланцюжок викликів збирається без ручного зіставлення форматів.

Збагачення подій додає до запису те, чого немає в самому рядку: вузол і версію релізу, зону доступності, власника сервісу.

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

Тоді причина інциденту знаходиться фільтром за атрибутами, а не за пам'яттю про те, хто як пише логи.

В експлуатації ефект видно у вимірюваних величинах: частка розпізнаних рядків сягає 98-99%, шлях від сигналу моніторингу до зрозумілої причини скорочується з годин до хвилин, а обсяг збереженого перестає зростати, бо сміттєві рядки відсікаються на вході.

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

Парсинг логів: розбір на вузлі чи централізований конвеєр

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

Точка розбору визначає, де витрачається процесор, який обсяг іде мережею і як швидко нові поля стають доступними для пошуку, оповіщень та кореляції.

Варіанти рідко конкурують напряму: робочі схеми комбінують розбір на вузлі для гарячих полів і централізований розбір для важких шаблонів. Межі застосовності кожного:

Варіант Коли підходить Обмеження
Розбір на вузлі Однотипні сервіси, стабільний формат, вузький канал зв'язку Витрачає процесор і пам'ять бойового хоста; шаблони треба синхронізувати по всіх вузлах; помилку видно лише на реальному трафіку
Централізований розбір Багато різнорідних джерел, спільне збагачення та маршрутизація Конвеєр стає точкою відмови: при сплеску зростає затримка і з'являються втрати; сировина все одно йде мережею
Потокова обробка подій Поля потрібні одразу — для оповіщень, метрик, кореляції Жорсткі вимоги до схеми та буферизації; збагачення на льоту дорожче за зберігання сирих даних
Відкладений розбір Архів, розслідування, рідко читані логи Поля з'являються із затримкою, оповіщення на них не побудувати, розбір за запитом сповільнює відповідь

Обмеження конвеєра проявляються не в самому розборі, а у версіонуванні шаблонів і контролі втрат. Якщо розібрані події не можна переграти із сировини, зміна формату логів дає сліпі зони — тому сирий лог зазвичай зберігають навіть при розборі на вузлі.

Як ми впроваджуємо розбір і збагачення подій: етапи

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

  1. Інвентаризація джерел логів. Обходимо застосунки, сервіси, балансувальники, планувальники завдань і бази: формат запису (структурований чи вільний текст), часовий пояс, добовий обсяг, наявність ідентифікатора запиту. Результат — реєстр джерел із відповідальним за кожен.
  2. Схема розбору. Для кожного типу події описуємо набір полів, а регулярні вирази залишаємо лише там, де структуру не віддає саме джерело. Схему перевіряємо на вибірці реальних записів, включно з багаторядковими трасуваннями помилок.
  3. Правила збагачення. Дописуємо те, чого немає в джерелі: прив'язку до сервісу та команди-власника, розшифрування кодів помилок, розмітку середовища, приведення рівнів важливості до спільного словника. Збагачення робимо в колекторі, а не в системі зберігання — правила живуть в одному місці.
  4. Перевірка на потоці. Нову схему вмикаємо паралельно з поточною і порівнюємо поля та частку розібраних подій на живому трафіку. Якщо частка нерозібраних записів вища за поріг, правило йде на доопрацювання, а не в основну гілку.
  5. Захист від сплесків і втрат. Задаємо розмір черги, поведінку при переповненні та контроль затримки доставки. Втрати й повтори вважаємо окремими метриками — конвеєр не повинен втрачати події мовчки.
  6. Передача конвеєра. Конфігурації, тести та опис полів кладемо в систему контролю версій, зміни проходять перевірку. Команді віддаємо регламент: як підключити нове джерело, як змінити правило, хто чергує і що дивитися при розходженні.

Конфігурації, схеми та регламенти: що залишається команді

Ми передаємо не набір разових правок, а робочий контур збору, який команда супроводжує сама. Усе, що описує поведінку конвеєра, лежить у системі контролю версій і узгоджується як звичайний код: історія змін відновлювана, відкат до попередньої версії займає хвилини.

  • Конфігурація конвеєра — опис приймання, розбору та маршрутизації подій окремими файлами, з шаблонами під кожен тип джерела і набором контрольних повідомлень для перевірки правок.
  • Схема потоків подій — звідки надходять дані, через які ланки проходять, де осідають і що відбувається при недоступності будь-якої з них; точки відмови позначені явно.
  • Шаблони розбору — правила під кожен формат джерела: структурований JSON, системний журнал, вільний текст. Окремо описано поведінку при появі незнайомих полів, щоб новий формат не ламав розбір цілком.
  • Політики доступу до подій — ролі та зони видимості: які потоки доступні якій команді, скільки вони зберігаються і в якому порядку видається доступ новому учаснику.
  • Правила маскування чутливих полів — що замінюється або хешується на вході, до потрапляння у сховище: облікові дані, ідентифікатори користувачів, персональні дані.
  • Регламент змін — хто пропонує правку, хто перевіряє, як вона обкатується на тестовому контурі, за яких умов відкочується і хто відповідає при інциденті.
  • Набір перевірок і метрик — контрольні події, що проганяються через конвеєр після кожної зміни, та оповіщення про втрату подій або зростання черги.

Після передачі розбираємо з командою реальні інциденти: де дивитися, що правити і як переконатися, що правка не зламала розбір. Далі контур живе без нас — підключаємося точково, коли змінюється джерело або зростає потік.

Кейс: розбір і збагачення подій у високонавантаженому сервісі

Високонавантажений сервіс писав події у сховище сирим текстом: один рядок змішував рівень важливості, ідентифікатор запиту, код відповіді та користувацькі дані.

Розбір виконувався вже в момент пошуку, шаблонами регулярних виразів, які ламалися на кожному нестандартному повідомленні.

Що було до змін

Третина подій не розбиралася: поля залишалися порожніми, а фільтри за кодом відповіді та сервісом повертали неповну картину.

Інженер на чергуванні шукав причину вручну, зіставляючи рядки очима, а сховище зростало швидше за трафік — дубльовані метадані зберігалися в кожному записі.

Що змінили

Розбір перенесли на етап приймання потоку: Grok розкладає повідомлення за іменованими полями, незіставлені події йдуть в окремий індекс із тегом, а не губляться. Записи збагачуються довідниками сервісів і власників, зайві поля відкидаються до запису на диск.

Метрика До Після
Частка нерозібраних подій 34% 1,2%
Пошук причини інциденту ~40 хвилин 4 хвилини
Обсяг сховища на той самий потік зростав лінійно утричі менше
Глибина розбору інциденту вибірково весь потік

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

Що робити, якщо сервіси пишуть події в неузгоджених форматах

Різнорідні формати логів — норма для зрілого продукту: один сервіс пише структурований JSON, другий — плоский текст із парами ключ-значення, третій — багаторядкові трасування помилок.

Переписувати їх заради однаковості ніхто не стане, тому приведення до єдиної схеми роблять на шарі збору: Fluentd або Logstash розбирає подію на вході, у сховище йде вже нормалізований запис.

Перший крок — зафіксувати обов'язковий мінімум полів: час, ім'я сервісу, рівень, ідентифікатор запиту; решта залишається розширюваною частиною. За основу імен беремо семантичні угоди OpenTelemetry — тоді вивантаження читає будь-який інженер, а не лише автор сервісу.

Правила зіставлення полів тримаємо декларативно: таблиця, де для кожного джерела описано, з якого ключа береться час, як розгортається вкладеність, що означає рівень.

Події, що не підійшли під жодне правило, не викидаємо, а складаємо в окремий потік — він же стає чергою завдань на доопрацювання розбору.

Схему версіонуємо: номер версії проставляється в саму подію при розборі, і споживачі якийсь час читають обидві версії паралельно. Це знімає головний ризик — перехід без зупинки сервісів і без одночасної правки всіх панелей та правил оповіщення.

Далі — поетапна міграція: спочатку новий розбір вмикають у режимі читання і звіряють результат зі старим, потім переводять споживачів, і лише потім вимикають застарілі правила.

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

Технічні сумніви: продуктивність, втрати та дублі

За цими сумнівами стоїть один ризик: збір логів перестає бути допоміжним і починає впливати на сервіси або на бюджет зберігання. Нижче — як кожен сценарій закривається в конфігурації агента та приймача.

Агент на кожному вузлі не сповільнить самі сервіси?

Читання йде окремим процесом з диска, піковий запис іде в буфер, а не в застосунок. Обмежуємо частку процесора та смугу відправлення, а при переповненні витісняємо низькопріоритетні потоки — транзакційні події залишаються.

Що станеться з подіями, якщо вузол або приймач впаде?

Доставка з підтвердженням і повторами: недослане лежить у локальному буфері. Після перезапуску агент дочитує файл з останньої підтвердженої позиції.

Повтори не дадуть дублів у звітах?

При повторах дублі можливі — це ціна гарантії доставки. Закриваємо ідемпотентністю: складений ключ із джерела та зміщення у файлі, повтори відкидаються при індексації, метрики рахуються за унікальними подіями.

Як збір переживає різкий сплеск навантаження?

Черга на диску згладжує сплеск: події чекають, а не губляться. Задаємо ліміти за обсягом і часом очікування, щоб черга не з'їла диск.

Обсяг зберігання не зросте швидше, ніж користь?

Парсинг на боці агента відкидає зайві поля до запису, а lifecycle-правила тримають гарячі дані окремо від теплих і чищають старе. Шумні джерела переводимо на вибірковий збір — реєстр перестає зростати лінійно.

Обговоримо задачу: розбір під ваш потік подій і склад даних

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

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

  • 5–10 прикладів сирих подій з кожного джерела — як є, разом із багаторядковими записами та явно нестандартними рядками: за ними підбираються шаблони розбору і перевіряється їхня стійкість.
  • Схема конвеєра на сьогодні: звідки беруться події, де стоїть збирач (Logstash або Fluentd), чи є проміжний буфер і хто читає результат — сховище, моніторинг чи аналітика.
  • Перелік полів, які потрібні в розібраному та збагаченому вигляді, і правила зв'язування: за адресою, ідентифікатором запиту, довідниками відповідності, гео- та сервісними атрибутами.
  • Профіль навантаження: середня та пікова частота подій, добове зростання, потрібна глибина зберігання і допустимий час затримки до появи запису у сховищі.
  • Вимоги до чутливих даних: що маскувати на вході, що вирізати повністю, скільки зберігати у відкритому вигляді і хто має доступ.
  • Доступи для пілотного сегмента: читання одного-двох джерел і майданчик, де розгорнемо контур, не зачіпаючи робочий потік.
  • Жорсткі обмеження: вікна обслуговування, вимоги до відкату, контури, куди дані не повинні йти.

Після розбору повернемося зі схемою конвеєра, порядком етапів плану впровадження та оцінкою робіт, розбитою за етапами. Пілотний сегмент запускаємо на одному-двох джерелах — якість розбору перевіряється на живому навантаженні до розкатки на весь потік. Опишіть задачу — надішлемо оцінку та план.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1543
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1374
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142