Логування
Логування — це слід, який залишає працююча система, щоб пізніше можна було відповісти на питання про неї, — і саме та частина експлуатації, яку найчастіше роблять так, що нею неможливо скористатися. Перевірка не в тому, скільки ви записуєте, а в тому, чи має відповідь питання, поставлене за три тижні, — і це вирішується тоді, коли пишеться код, а не коли починається інцидент. На цій сторінці — чому рядок логу має бути подією, а не реченням, для чого потрібні логи порівняно з метриками й трасуванням, які поля роблять інцидент відповідним на питання і яка арифметика перетворює звичку логувати на рахунок, якого ніхто не передбачав.
- Рядок логу — це
- Подія, а не проза
- Вирішується коли
- Пишеться код
- Що жене вартість
- Обсяг × зберігання
Рядок логу — це подія, а не речення
Більшість коду логування пишеться для уявного читача: людини, що гортає термінал тієї миті, коли все ламається. Такого читача майже ніколи не існує. Справжній читач — це запит, надрукований за тижні кимось, кого там не було, з питанням, скількох користувачів це зачепило, чи почалося воно з останнього релізу і чи триває досі. Речення не відповідає на жодне з них. Запис із полями відповідає на всі три.
Практична зміна невелика: віддавайте обʼєкт замість відформатованого рядка й кладіть кожен факт, який ви вставили в повідомлення, ще й у власне поле. Не вдалося списати кошти з картки користувача 8213 після 3 спроб стає подією з назвою payment_failed і полями user_id, attempts та reason поруч. Лишіть і читабельне повідомлення, якщо хочете, — нічого не втрачається, — але саме поля роблять запис таким, що рахується. І вживайте одну назву поля в усіх сервісах, бо user_id в одному сервісі й userId в іншому — це дві колонки для рушія запитів і один дуже дратівливий день для людини.
Логи, метрики й трасування відповідають на різні питання
Команди, що логують усе, зазвичай роблять це тому, що логи — єдиний сигнал, який у них є; вони платять за це сховищем і при цьому досі не можуть відповісти на базові питання. Три сигнали — це не три формати однієї речі: у них різна форма, різна вартість і різні межі, і знати, яке питання кому належить, — це більша частина вміння.
| Сигнал | На яке питання відповідає | Чого коштує і де спиняється |
|---|---|---|
| Метрики | «Чи щось не так і відколи?» Числа, агреговані в часі: темпи, затримки, кількості. | Дешеві й сталі на серію, тож тримайте їх довго. Вони нічого не скажуть про один конкретний запит. |
| Логи | «Що саме сталося з цим одним обʼєктом?» Окремі події з непошкодженими деталями. | Вартість росте з трафіком, тож зберігання — рішення бюджету. Погані для трендів: рахувати їх дорого. |
| Трасування | «Куди пішов час — через усі сервіси?» Один запит як дерево відрізків із часом. | Зазвичай із вибіркою, бо тримати всі траси не по кишені. Слабкі для рідкісного, якщо вибірка не розумна. |
Корисна дисципліна випливає з таблиці. Алертуйте за метриками: вони достатньо дешеві, щоб обчислювати їх постійно, і достатньо стійкі, щоб не спрацьовувати на одному поганому запиті. Діагностуйте трасуванням: воно показує, куди пішов час, без вгадування, у який сервіс дивитися. Підтверджуйте логами: саме там живуть деталі конкретного випадку, що впав. Команда, яка алертує за пошуком у логах, платить рушію запитів за роботу метрики — і це буде і повільніше, і дорожче рівно тієї миті, коли це важить.
Поля, що роблять інцидент відповідним на питання
Короткий і нудний список покриває більшість. Кожна подія з кожного сервісу має нести ці поля — не тому, що так каже стандарт, а тому, що кожне з них є питанням, яке хтось поставить, поки клієнт чекає.
Ідентифікатор трасування
Найцінніше поле на цій сторінці. Воно звʼязує кожен рядок логу з кожного сервісу з однією дією користувача. Створіть його на межі, передавайте всюди, логуйте завжди.
Назва події
Стала назва низької кардинальності із закритої множини. Саме її ви рахуєте, групуєте й берете в алерт, коли зрештою перетворюєте лог на метрику.
Сервіс і реліз
Який код це видав. Без релізу питання «чи спричинило це розгортання» не має відповіді, — а воно перше в більшості інцидентів.
Актор і тенант
З ким це сталося — ідентифікатором, а не імʼям чи поштою. Потрібно, щоб відповісти про масштаб: один клієнт, один регіон чи всі.
Результат і причина
Успіх чи провал і код причини із закритої множини. Саме лише «провал» змушує людину читати повідомлення; код причини можна згрупувати.
Тривалість
Скільки тривала операція, у мілісекундах, числом. Записати нічого не коштує, а на питання «чи було повільно до поломки» відповідає безкоштовно.
Двох речей у лозі бути не має. Персональних даних — імен, адрес, пошт, номерів карток, токенів, повних тіл запитів, — бо логи копіюються на пошукову платформу, лежать місяцями й читаються більшою кількістю людей, ніж ваша база, а це робить їх найімовірнішим місцем витоку, який ніхто не аудіював. І будь-чого, що ви не можете дозволити собі надрукувати, а на практиці це облікові дані: рядок логу — класичний шлях, яким секрет тікає із системи, обережної в усьому іншому. Логуйте ідентифікатор, а запис із бази дістаньте тоді, коли він справді знадобиться.
Арифметика, що стає рахунком
Вартість логування — це одне множення, і зробити його один раз означає уникнути несподіванки. Візьміть запити на секунду, помножте на рядки логу на запит, на байти в рядку і на секунди в добі. Сервіс на 500 запитів за секунду, що пише 8 рядків по 600 байтів, дає близько 200 ГБ на добу — з одного сервісу. Помножте на кількість сервісів, потім на строк зберігання, потім на те, що платформа бере за прийом і за індексацію, — а це зазвичай два окремі рахунки. Більшість команд знайомиться з цим числом уперше в інвойсі.
Керують цим чотири важелі, і тягнути їх варто в такому порядку:
- Перестаньте логувати те, що ніхто не запитує. Більшість обсягу — це кілька рядків на гарячому шляху, доданих під час налагодження роки тому й ніколи не прибраних.
- Робіть вибірку успішних і тримайте всі провали. Нікому не потрібен кожен з мільйона однакових успіхів, і всім потрібен кожен провал.
- Ешелонуйте зберігання: із пошуком — два тижні, дешевий архів — на строк відповідності. Майже кожен запит стосується останніх кількох днів.
- Перетворіть найоб’ємніші події на метрики й перестаньте зберігати їх поодинці: лічильник відповідає на «скільки» за похибку від тієї вартості.
Як зробити інцидент відповідним від краю до краю
У системі з одного сервісу логи — це файл. У системі з кількох це купа файлів, що описують ту саму дію користувача з пʼяти боків і не зʼєднуються — якщо тільки щось не було пронесено між ними. Це щось — ідентифікатор трасування, створений у першій точці входу запиту у вашу систему й переданий далі в заголовку, а потім причеплений до кожного рядка логу, який цей запит породжує будь-де. Це кілька годин сантехніки — і це різниця між реконструкцією інциденту й припущеннями про нього.
Ще дві звички відділяють сховище логів від придатного до вжитку. Віддавайте однакові назви полів усюди: домовтеся про них один раз, покладіть у спільну бібліотеку й не дозволяйте кожному сервісу вигадувати власні. І користуйтеся однією відкритою конвенцією, а не форматом вендора: OpenTelemetry дає ідентифікатор трасування, ідентифікатор відрізка й набір стандартних назв атрибутів, а отже, збір і платформу можна замінити, не чіпаючи коду застосунку. Друге з часом важить більше, ніж здається зараз, бо платформа логів — той компонент, який команди найчастіше хочуть змінити й найрідше можуть.
Антипатерни, які варто назвати
- Повідомлення, зібрані з шаблонів: кожен рядок — унікальний рядок, і без регулярного виразу нічого не порахувати.
- Залогувати виняток і кинути його далі: один збій зʼявляється чотири рази на чотирьох рівнях стека.
- Персональні дані в полях, що лежать девʼяносто днів на платформі зі ширшим списком доступу, ніж у базі, звідки вони взялися.
- DEBUG, лишений увімкненим у проді після розслідування, — його виявляє наступного місяця фінансовий відділ.
- Немає ідентифікатора трасування: інцидент між сервісами реконструюють, порівнюючи мітки часу й сподіваючись, що годинники згодні.
- Алерти за пошуком у логах: це робота метрики, яку виконує рушій запитів у найгіршу можливу мить.
Коли це застосовувати
Застосовуйте, коли
- Будь-що, що працює без нагляду: лог — єдина розповідь про те, що сталося, яка переживе процес.
- Розслідування окремого випадку — це замовлення, цей користувач, цей запит, — де агрегат не допоможе.
- Запис бізнес-подій, які згодом треба рахувати чи аудіювати, де назва події є одиницею аналізу.
- Будь-яка система, де запиту торкається більш ніж один сервіс, — за умови, що між ними несеться ідентифікатор трасування.
Уникайте, коли
- Як джерело алертів чи дашбордів, яким лічильник послужить краще, швидше й за частку ціни.
- Як сховище будь-чого персонального чи таємного: і строк зберігання, і доступ ширші, ніж вам здається.
- На гарячому шляху з рядком на елемент, де обсяг коштує більше за цінність інформації й гальмує сам запит.
- Як заміну трасуванню, коли питання в тому, куди пішов час: лог не має поняття відрізка.
Було корисно?
Поділіться з тим, хто працює над тією ж задачею.