Логування — це не “пишемо щось у файл”. Це ваша система спостереження за продуктом у продакшені. Коли щось ламається вночі, коли користувач каже “не працює”, коли рахунок не згенерувався, коли статус не оновився, коли запит раптово став повільним — у вас є два варіанти: або ви дістаєте відповідь із логів за хвилину, або ви тижнями “відтворюєте” проблему. На масштабі другий варіант з’їдає час, гроші й нерви.
Щоб логування реально допомагало, треба одразу визначити, що саме ви логуватимете. Логи потрібні для трьох речей: пошуку причин помилок (debugging), контролю безпеки (audit/security), контролю якості роботи системи (observability). Якщо ви пишете в лог “будь-що й будь-коли”, він стає шумом. Якщо ви не пишете критичні події — він стає марним. Тому потрібна політика: які події важливі, який рівень, які поля, яка частота, і як по цих логах шукати.
Найкорисніші категорії логів — це початок/кінець запиту, бізнес-подія, зовнішній виклик, помилка, і фонові задачі. Для HTTP-запиту корисно бачити метод, шлях, статус, тривалість у мілісекундах, ідентифікатор користувача (якщо є), і correlation id. Для бізнес-події корисно бачити “що саме відбулося” мовою домену: “створено новину”, “оновлено статус рахунку”, “змінено approval_status”, “прикріплено медіа”, “виконано публікацію в соцмережі”. Для зовнішнього виклику (API/вебхук) корисно фіксувати endpoint, код відповіді, тривалість, і коротку причину помилки, якщо вона сталася. Для помилок потрібно логувати exception, стек, контекст і вхідні параметри, але без витоку секретів. Для background jobs потрібно логувати старт/фініш, кількість спроб, причину фейлу і той самий correlation id, щоб з’єднати їх із початковим запитом.
Окрема дисципліна — що НЕ логувати. Ніколи не пишіть у логи паролі, токени доступу, cookie, CSRF-токени, ключі API, приватні ключі, повні реквізити карток, повні персональні дані, і сирі дампи всіх полів форми “як є”. Це прямий ризик витоку, і на практиці це рано чи пізно стає інцидентом. Якщо треба розуміти, що надійшло у запиті, логують лише whitelist ключів і в безпечному вигляді: наприклад, “email замаскований”, “ідентифікатор сутності”, “кількість елементів”, “тип файлу і розмір”, але не вміст.
Далі — рівні логування. Рівень потрібен, щоб відділити інформацію для розробника від сигналів для моніторингу і алертів. У типових системах (і в Laravel через Monolog) лог-левели йдуть від найкритичнішого до найдетальнішого: emergency/alert/critical/error/warning/notice/info/debug. На практиці вам важливо навчитися відчувати межі. Error — коли операція не виконана і користувач/система отримали збій. Warning — коли операція виконалась, але є ризик або деградація (наприклад, “повільний запит”, “ретрай зовнішнього API”, “не вдалося записати другорядний лог/метрику”). Info — це бізнес-і технічні події “нормального життя”: створено/оновлено/видалено, старт/фініш job, успішна інтеграція. Debug — це тимчасова деталізація для розробки і коротких розслідувань, яка у проді або вимикається, або сильно обмежується, бо інакше вона вб’є і диски, і читабельність.
Найчастіша помилка з рівнями — логувати все як info або все як error. Якщо все info, то реальні проблеми губляться. Якщо все error, то алерти стають постійними, команда “звикає” і пропускає реальні аварії. Тому правило просте: error має бути рідкісним і болючим, warning має бути керованим і мати перспективу “виправити”, info має бути достатнім для відновлення історії дій без зайвого шуму, debug має бути дозованим.
Тепер ключова тема — correlation id. Це ідентифікатор “ланцюжка” виконання, який дозволяє з’єднати в один сюжет усі логи, пов’язані з конкретним запитом або операцією. У складних системах без цього ви приречені: один клік у адмінці запускає HTTP-запит, всередині йде кілька SQL, далі відправляється job у чергу, job робить ще запити, пише activity, викликає зовнішній сервіс. Якщо ви не маєте correlation id, ці логи розсипані й не збираються в один пазл. Якщо correlation id є, ви за ним знаходите весь “трейс” за секунди.
Правильна практика така: correlation id генерується на вході кожного HTTP-запиту (або береться з заголовка, якщо його вже дав проксі/клієнт), і далі додається в контекст кожного лога під час обробки цього запиту. У відповідь ви теж повертаєте цей id в заголовку, щоб якщо користувач дає вам скрін “помилка”, ви могли попросити “дай Request ID” і одразу знайти точний ланцюжок. У Laravel це зазвичай робиться middleware, який встановлює X-Request-Id (або X-Correlation-Id) і додає його в Log context.
Найважливіше: correlation id має “переїжджати” в черги та фонові задачі. Інакше у вас буде request id для веб-запиту і окремі “анонімні” логи для job, і зв’язок втрачено. Тому коли ви диспатчите job, ви передаєте correlation id у payload або встановлюєте його в контексті job на старті. Тоді весь життєвий цикл операції — від кліку до фонового завершення — читається як одна історія.
Щоб correlation id був реально корисним, лог має бути структурованим, а не просто “рядок тексту”. Мінімальний набір полів, який робить логи діагностичними: timestamp, level, message, correlation_id, user_id (якщо є), route/path, method, status_code, duration_ms, entity_type/entity_id (якщо це бізнес-дія), і для помилок — exception class і короткий error code. Без цих полів ви все одно будете гадати. З ними ви отримуєте пошук і фільтрацію, а не ручне читання тисяч рядків.
Є ще практичний момент, який відразу впливає на майбутнє: логування має бути керованим за обсягом. Якщо ви логуватимете всередині циклу по 500 елементів на кожен елемент, ви “вб’єте” диск і ускладните розслідування. Якщо вам треба бачити масову операцію, логують підсумки: “оброблено 500, успішно 492, помилок 8, приклади помилок…”, а детальні записи роблять лише для помилок або через debug з семплінгом.
Нарешті, логування має мати “продовження” у вигляді спостереження. Якщо error/critical не піднімає сигнал, ви дізнаєтесь про проблему від користувача. Якщо warning про повільні запити ніхто не дивиться, через місяць у вас буде деградація продуктивності “незрозуміло чому”. Тому політика логів завжди повинна думати наперед: які рівні ми моніторимо, які алерти вмикаємо, яка ретенція логів, як їх шукати, і хто відповідає за реакцію.
Висновок такий: хороше логування — це мінімум шуму і максимум відновлюваності історії. Логуйте події, які пояснюють “що сталося” і “чому”, використовуйте рівні так, щоб вони мали сенс, і обов’язково впровадьте correlation id, який проходить через HTTP і черги. Без correlation id ви завжди будете розслідувати “в темряві”. З ним — ви будуєте систему, яку реально підтримувати й масштабувати без постійних пожеж.