Повний посібник з моніторингу React-застосунків за допомогою Grafana Faro

Повний посібник з моніторингу React-застосунків за допомогою Grafana Faro

У цій статті ми детально розглянемо процес інтеграції React-застосунку з Grafana Faro — нашим інструментом для frontend-моніторингу (observability). Ми вивчимо, як Grafana Faro допомагає візуалізувати критично важливу інформацію, таку як продуктивність застосунку, помилки, логи та активність користувачів за допомогою моніторингу реальних користувачів (Real User Monitoring, RUM).

Чому observability — це важливо

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

Одним із ключових компонентів frontend-моніторингу є Real User Monitoring (RUM). RUM відстежує та аналізує, як реальні користувачі взаємодіють із вашим застосунком. Він збирає такі дані, як час завантаження сторінок та користувацькі взаємодії, допомагаючи ефективно адаптувати застосунок до реальних сценаріїв використання.

Ще один критичний аспект — розуміння Web Vitals. Це метрики, які Google вважає важливими для хорошого користувацького досвіду в інтернеті. До них належать:

  • Largest Contentful Paint (LCP) — вимірює продуктивність завантаження.
  • First Input Delay (FID) — вимірює інтерактивність.
  • Cumulative Layout Shift (CLS) — вимірює візуальну стабільність у застосунку.

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

Саме тут на допомогу приходить Grafana Faro. Інструмент надає інтегрований набір рішень, розроблених спеціально для frontend-застосунків. Він дозволяє збирати, аналізувати та візуалізувати ключові показники продуктивності, помилки та патерни використання в режимі реального часу.

Faro постачається з попередньо налаштованими дашбордами, які автоматично відображають ці метрики, спрощуючи налаштування моніторингу та дозволяючи зосередитися на оптимізації застосунку на основі реальних користувацьких даних. Він також включає функції для відстеження шляху користувачів (user journeys) та їхньої поведінки, даючи глибоке розуміння того, як користувачі взаємодіють з інтерфейсом і де вони стикаються з труднощами.

Контекст застосунку та завдання моніторингу

Для демонстрації ми будемо використовувати запущений React-застосунок. Цей застосунок звертається до стороннього API, розгорнутого у хмарі, яке, своєю чергою, підключається до API магазину Steam для повернення всіх рекомендованих ігор, представлених на даний момент у магазині.

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

Однак, якщо спробувати виконати пошук прямо зараз, ми зіткнемося з помилками часу виконання (runtime issues). Це показовий приклад того, з чим може зіткнутися користувач під час роботи з вашим застосунком у production. Під час локальної розробки помилку легко відстежити, але коли застосунок використовується кінцевими користувачами, ви не зможете безпосередньо побачити, що вони зіткнулися з проблемою. Нам потрібен спосіб візуалізувати це на дашборді Grafana.

Я хочу впровадити телеметрію в цей веб-застосунок, щоб ми могли почати збирати інформацію про такі показники, як час завантаження сторінок, Time to First Byte (TTFB), бачити генеровані логи та фіксувати будь-які помилки, з якими можуть зіткнутися користувачі.

Налаштування Grafana Cloud Frontend Observability

Для початку налаштування я переходжу у свій інстанс Grafana Cloud і в лівому бічному меню вибираю розділ Frontend App. Тепер я перебуваю в розділі Grafana Faro (відомому в Grafana Cloud як Frontend Observability).

Я створюю новий застосунок і називаю його Folly demo (Front-end observability demo).

Нижче знаходиться розділ CORS allowed origins. Він дозволяє визначити, яким URL-адресам дозволено надсилати дані в колектор Grafana Faro. Оскільки мій застосунок працює локально на машині за адресою localhost на порту 3000, я вводжу http://localhost:3000, обов’язково вказуючи протокол HTTP.

Під ним розташований розділ Default attributes. Він дозволяє додавати метадані до всіх логів, подій та помилок, які надходять у колектор за замовчуванням. Завдяки цьому нам не потрібно вручну додавати їх до кожної події, що надсилається із застосунку. Це економить пропускну здатність і гарантує, що задані параметри завжди будуть присутні. Я додам параметр application name зі значенням steam store front end, щоб надалі ми могли легко шукати за ним у логах.

Далі я підтверджую, що створення цього ресурсу потягне за собою певні витрати, і натискаю кнопку створення.

Встановлення пакетів та ініціалізація SDK

Після створення ресурсу нас перенаправляє в застосунок Frontend Observability, спеціально створений для Folly demo, на вкладку конфігурації Web SDK. За замовчуванням тут подано інструкцію з інтеграції застосунку шляхом додавання стартового коду. Я скопіюю цей блок коду, але ми внесемо в нього деякі зміни.

У базовому вигляді цей код імпортує залежності з пакета @grafana/faro-web-sdk. Однак наш застосунок використовує React, а не стандартний JavaScript. Для роботи з React існує спеціальний пакет.

Переходимо до коду нашого застосунку, зупиняємо його роботу та виконуємо встановлення npm-пакетів. Замість faro-web-sdk ми встановлюємо пакет @grafana/faro-react, а також пакет @grafana/faro-web-tracing.

Після встановлення цих пакетів вставляємо скопійований код ініціалізації та вносимо в нього такі зміни:

  1. Змінюємо імпорт, щоб він ішов із пакета Faro React, а не з Faro Web SDK.
  2. Видаляємо змінну faro на початку ініціалізації, оскільки безпосередньо в цьому блоці вона використовуватися не буде.
  3. Інтегруємо React Router, щоб почати отримувати інформацію про завантаження сторінок та помилки в контексті окремих маршрутів (наприклад, Home, Favorites, Search).

Для цього імпортуємо необхідні залежності з react-router у верхній частині файлу, а також додаємо компоненти з пакета Faro React: ReactIntegration та reactRouterVersion.

Далі в розділі instrumentations конфігурації Faro додаємо нову інтеграцію — ReactIntegration. Тут ми вказуємо властивість router, задаємо версію reactRouterVersion: 6 і передаємо залежності, імпортовані раніше.

Зберігаємо цей файл і переходимо до файлу app.js, де визначені маршрути нашого застосунку. Замість використання стандартного компонента Routes з React Router, ми будемо використовувати компонент FaroRoutes. Видаляємо імпорт об’єкта Routes та імпортуємо FaroRoutes з пакета Faro React, після чого зберігаємо зміни.

Генерація даних та аналіз дашборда

Знову запускаємо застосунок за допомогою npm start. Щоб згенерувати дані для аналізу, необхідно виконати кілька дій: оновлюємо сторінку, переходимо в розділ обраного, видаляємо пару ігор, повертаємося назад і додаємо інші ігри до обраного. Потім виконуємо кілька пошукових запитів. Я шукаю «Final Fantasy» і знову отримую повідомлення про помилку. Повертаюся на сторінку пошуку, шукаю «Broken Sword» — і знову стикаюся з помилкою.

Тепер переходимо на вкладку Overview у розділі Frontend Observability у Grafana Cloud. У правій частині екрана змінюємо значення у випадному меню автооновлення на «кожні 5 секунд». Щойно сторінка оновиться, ми побачимо інформацію, яка була відправлена в інстанс Grafana Faro.

Ми бачимо, що зафіксовано 7 завантажень сторінок. У верхній частині представлена вся аналітика щодо Web Vitals:

  • Time to First Byte
  • First Contentful Paint
  • Largest Contentful Paint
  • Cumulative Layout Shift
  • First Input Delay
  • Interaction to Next Paint

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

Під ними знаходиться розділ продуктивності сторінок (Page Performance). Оскільки ми налаштували інтеграцію з React Router, вся інформація розбита за маршрутами. Дані відображаються окремо за розділом Favorites, сторінкою Search та кореневою сторінкою. Нижче розташовані три панелі з показниками 75-го процентиля для таких метрик, як Page Load, Cumulative Layout Shift та Input Response Time. Це дає загальне уявлення про те, який досвід отримує переважна більшість користувачів.

Налагодження помилок (Debugging)

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

Переходимо на вкладку Errors. Тут знову відображається таймлайн завантажень сторінок та помилок, а також розділи “Top errors” і “Top page routes by error count”. Ці графіки відразу показують, що у нас падає запит із кодом 404, і це відбувається на сторінці Search.

Клікнувши на помилку, ми отримуємо повний стек-трейс (stack trace). Це помилка Axios: Request failed with status code 404, що сталася на сторінці пошуку.

Повернувшись на дашборд Overview, ми вже знаємо, що помилка локалізована на сторінці пошуку і має статус 404. Можна відразу піти в код і перевірити URL, але є ще один корисний інструмент. Ми переходимо в розділ Search, де відображаються всі користувацькі сесії (Session ID).

Клікнувши на Session ID, ми відкриваємо деталі сесії. Тут зібрана вся інформація про шлях конкретного користувача в застосунку — всі події та вимірювання. У розділі активності (Activity) перемикаємося на вкладку Traces, яка показує всі трейси всередині застосунку, включаючи безліч GET-запитів до сторонніх сервісів.

Аналізуючи їх, ми бачимо успішний GET-запит зі статусом 200 OK до ендпоінта featured нашого Steam API. Наступний запит теж повертає 200 OK. Переглядаючи далі, ми знаходимо проблемний ендпоінт із помилкою 404. Запит іде до ендпоінта games і шукає гру «Final Fantasy». Однак в URL-адресі є очевидна помилка (описка): слово написано як gamess із двома літерами s замість однієї.

Повертаємося в код застосунку на сторінку пошуку і виправляємо цей URL. Зберігаємо файл, повертаємося в застосунок і повторюємо пошук «Final Fantasy». Тепер результати успішно повертаються.

Кастомні логи та події (Custom Logs & Events)

Крім базової аналітики (Web Vitals, відстеження завантажень сторінок та роутів), до логів і подій, що відправляються у Grafana Faro, можна додавати додатковий контекст. Це дозволяє краще розуміти шлях користувача — наприклад, логувати сам факт пошуку та кількість знайдених результатів.

У коді сторінки пошуку, відразу після отримання результатів відповіді API, ми додаємо кастомний запис у лог. Для цього імпортуємо об’єкт faro та LogLevel із пакета faro-react.

Використовуючи функцію faro.api.pushLog, ми передаємо рядок: Search result for [Search Term] found [Length] games. Ми змінюємо рівень логування з warn на info і передаємо додатковий контекст: searchTerm, results та userId. Оскільки Faro очікує рядкові значення, довжину масиву результатів можна конвертувати в рядок за допомогою інтерполяції.

Також ми можемо відправити кастомну подію (event). Використовуючи той самий Faro API, викликаємо функцію faro.api.pushEvent. Задаємо ім’я події, передаємо додатковий контекст і вказуємо домен, до якого ця подія належить.

Кастомна обробка помилок

Щоб застосунок коректно реагував на непередбачувані збої в розділі пошуку, обгортаємо весь блок запиту в try/catch.

Усередині блоку catch ми викликаємо faro.api.pushError, явно передаючи спійману помилку у Faro. Тут же ми викликаємо метод setIsLoading(false), щоб приховати нескінченний спінер завантаження в інтерфейсі. Тепер, якщо URL буде вказано неправильно або виникне проблема під час парсингу відповіді, ця конкретна помилка безпосередньо відправиться у Grafana Faro, а користувач не зависне на екрані безперервного завантаження.

Перевірка телеметрії через Loki Logs

Повертаємося в застосунок і тестуємо нові логи. Вводимо в пошук «Broken Sword» та «Master Chief», додаємо знайдені результати до обраного.

У дашборді Frontend Observability у Grafana Cloud, у розділі Page Performance, ми клікаємо на ендпоінт пошуку, розгортаємо сесію користувача і натискаємо Explore, щоб переглянути логи Loki для цієї конкретної сесії.

У конструкторі запитів (Builder) для логів додаємо новий фільтр за міткою (label filter). Вибираємо kind і шукаємо будь-які події (events) для даного користувача за останні 30 хвилин.

У результатах ми бачимо подію з ім’ям search. У її деталях міститься весь додатковий контекст, який ми відправили з коду: searchTerm дорівнює “Master Chief”, а userId збігається з ID користувача в застосунку.

Потім ми змінюємо значення фільтра kind на log, щоб побачити відправлений кастомний запис логу. У панелі з’являється повідомлення: Search result for Master Chief found 1 game, а нижче відображається переданий нами контекст із пошуковим запитом, кількістю результатів та ідентифікатором користувача.

За допомогою описаних кроків ми успішно інтегрували телеметрію в React-застосунок із використанням Grafana Faro SDK та налаштували моніторинг через Frontend Observability у Grafana Cloud. Цей стек надає вичерпний набір інструментів для контролю продуктивності, відстеження поведінки реальних користувачів та оперативного виявлення помилок на стороні клієнта.