В этой статье мы подробно рассмотрим процесс интеграции 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.
После установки этих пакетов вставляем скопированный код инициализации и вносим в него следующие изменения:
- Меняем импорт, чтобы он шел из пакета Faro React, а не из Faro Web SDK.
- Удаляем переменную
faroв начале инициализации, так как напрямую в этом блоке она использоваться не будет. - Интегрируем 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. Этот стек предоставляет исчерпывающий набор инструментов для контроля производительности, отслеживания поведения реальных пользователей и оперативного выявления ошибок на стороне клиента.