
Введение
Здравствуйте. В данной статье будет выполнено рассмотрение и установка инструмента Grafana Faro для осуществления сбора данных мониторинга из Frontend приложений написанных на JavaScript. Также, перед непосредственным использованием Grafana Faro, выполним установку в кластере Kubernetes всех остальных необходимых компонентов Grafana стека.
Инструмент Grafana Faro представляет собой набор пакетов, подключение которых осуществляется в Frontend JavaScript приложениях. Подключаемые пакеты позволяют выполнить сбор различных данных мониторинга, существуют следующие пакеты:
grafana/faro-web-sdk или grafana/faro-react (при использовании React) — данные пакеты осуществляют сбор таких данных, как:
Метрики Core Web Vitals — скорость загрузки основного контента (LCP), время ожидания до первого взаимодействия с контентом (FID), совокупное смещение макета (CLS), время до первого байта (TTFB), первая отрисовка содержимого (FCP);
Необработанные исключения;
Сообщения выведенные в консоль;
События изменения view;
События начала и продолжения сессий;
grafana/faro-web-tracing — пакет осуществляет интеграцию в приложение сбора трейсов на основе OpenTelemetry.
Далее данные мониторинга полученные с помощью пакетов Grafana Faro отправляются в Grafana Alloy, который выполняет обработку полученных метрик и после этого метрики полученные из пакетов:
grafana/faro-web-sdk или grafana/faro-react (при использовании React) - отправляются в систему логирования Grafana Loki;
grafana/faro-web-tracing - отправляются в систему трассировки Grafana Tempo.
Отображение и визуализация полученных метрик осуществляется с использованием Grafana.
Общую структурную схему работы рассматриваемого решения для сбора данных мониторинга из Frontend JavaScript приложений можно увидеть на рисунке ниже:

Установка компонентов Grafana стека в Kubernetes
Для осуществления сбора данных мониторинга выполним создание тестовый среды с установкой инфраструктурных компонентов Grafana стека в кластера Kubernetes используя Helm.
Создадим отдельный неймспейс в который будем выполнять установку компонентов с использованием команды:
$ kubectl create namespace monitoring
Далее выполним подключение Helm репозитория Grafana с помощью команды:
$ helm repo add grafana https://grafana.github.io/helm-charts
Установка Grafana Loki
Выполним создание файла values-loki.yaml содержащий значения Helm для выполнения установка Grafana Loki, в данном примере значения подготовлены для установки в монолитном режиме с отключенной авторизацией и использованием S3 хранилища MinIO:
loki: auth_enabled: false commonConfig: replication_factor: 1 schemaConfig: configs: - from: 2024-04-01 store: tsdb object_store: s3 schema: v13 index: prefix: loki_index_ period: 24h ingester: chunk_encoding: snappy tracing: enabled: true querier: max_concurrent: 2 gateway: enabled: false deploymentMode: SingleBinary singleBinary: replicas: 1 chunksCache: writebackSizeLimit: 10MB minio: enabled: true backend: replicas: 0 read: replicas: 0 write: replicas: 0 ingester: replicas: 0 querier: replicas: 0 queryFrontend: replicas: 0 queryScheduler: replicas: 0 distributor: replicas: 0 compactor: replicas: 0 indexGateway: replicas: 0 bloomCompactor: replicas: 0 bloomGateway: replicas: 0
Далее выполним установку Grafana Loki используя команду:
$ helm install loki grafana/loki --namespace=monitoring --values values-loki.yaml
Установка Grafana Tempo
Подготовим файл values-tempo.yaml c добавлением значений Helm для установки Grafana Tempo, в данном примере будут использоваться все стандартные значения с единственным изменением — включением постоянного хранилища:
persistence: enabled: true
Выполним установку Grafana Tempo:
$ helm install tempo grafana/tempo --namespace=monitoring --values values-tempo.yaml
Установка Grafana Alloy
Далее выполним создание Helm Values файла values-alloy.yaml для установки Grafana Alloy, в данном примере выполнена настройка конфигурационного файла Alloy в котором подключен приёмник Faro с отправкой в Loki и отправку через OpenTelemetry Collector в Tempo. Дополнительно в настройках приёмника Faro выполняется конфигурирование:
используемого порта;
настройки CORS;
ключа API через который будет выполнять отправку метрик Faro;
максимальный разрешённый размер полезной нагрузки;
указание rate лимита.
Также в values файле выполнено добавление extraPort для Faro, так-как по умолчанию в helm значениях создаётся только порт для web-интерфейса Grafana Alloy. Дополнительно выполнено включение ingress c указанием порта Faro, в дальнейшем указанный адрес в ingress будет использоваться при подключении Grafana Faro в Frontend JS приложениях, важно чтобы указанный адрес был доступ для подключения со стороны клиентов использующих приложение, иначе отправка метрик будет невозможна:
alloy: configMap: create: true content: |- faro.receiver "frontend_applications" { server { listen_address = "0.0.0.0" listen_port = 8030 cors_allowed_origins = ["http://example-frontend-app.local.ru"] api_key = "api-key-app" max_allowed_payload_size = "5MiB" rate_limiting { rate = 100 } } sourcemaps { } output { logs = [loki.process.logs_process.receiver] traces = [otelcol.exporter.otlp.trace_write.input] } } loki.process "logs_process" { forward_to = [loki.write.logs_write.receiver] stage.logfmt { mapping = { "kind" = "", "service_name" = "", "app_name" = ""} } stage.labels { values = { "kind" = "kind", "service_name" = "service_name", "app" = "app_name" } } } loki.write "logs_write" { endpoint { url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push" } } logging { level = "info" } otelcol.receiver.otlp "default" { grpc { include_metadata = true } output { metrics = [] logs = [] traces = [otelcol.exporter.otlp.trace_write.input] } } otelcol.exporter.otlp "trace_write" { retry_on_failure { max_elapsed_time = "1m0s" } client { endpoint = "tempo.monitoring.svc.cluster.local:4317" tls { insecure = true } } } extraPorts: - name: "faro" port: 8030 targetPort: 8030 protocol: "TCP" ingress: enabled: true path: / faroPort: 8030 pathType: Prefix hosts: - alloy.local
Выполним установку Grafana Alloy с помощью команды:
$ helm install alloy grafana/alloy --namespace=monitoring --values values-alloy.yaml
Проверим корректность установки Grafana Alloy с помощью web-интерфейса, для этого выполним перенаправление порта с помощью команды:
$ kubectl port-forward svc/alloy 8080:12345 -n monitoring
Далее в браузере перейдём по адресу http://localhost:8080/ и увидим успешное подключение всех компонентов:

Установка Grafana
Выполним подготовку значений Helm в файле values-grafana.yaml для установки Grafana, в созданном values файле добавлены значения источников данных Loki и Tempo, а также выполнено создание постоянного хранилища и ingress:
persistence: enabled: true ingress: enabled: true hosts: - grafana.local datasources: datasources.yaml: apiVersion: 1 datasources: - name: loki type: loki url: http://loki.monitoring.svc.cluster.local:3100 access: proxy isDefault: true - name: tempo type: tempo url: http://tempo.monitoring.svc.cluster.local:3100 access: proxy
Выполним установку Grafana:
$ helm install grafana grafana/grafana --namespace=monitoring --values values-grafana.yaml
После завершения установки Grafana выполним получения пароля для пользователя admin с помощью команды:
$ kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
Перейдём в web-интерфейс Grafana по адресу добавленному в ingress, далее в разделе Dashborad, выберем New — Import и выполним импорт дашборда для отображения будущих собираемых метрик. JSON дашборда для Grafana Faro доступен в официальном GitHub репозитории.

Подключение Grafana Faro в приложении
Выполним установку пакетов Grafana Faro используя команду:
$ npm install --save @grafana/faro-web-sdk @grafana/faro-web-tracing
Далее в Frontend JavaScript приложении выполним добавление кода осуществляющий инициализацию Grafana Faro для сбора метрик и трейсов. В коде необходимо указание: названия приложения, его версии, а также API ключа и адреса ингресса Grafana Alloy созданного нами ранее при его установке:
import { getWebInstrumentations, initializeFaro } from '@grafana/faro-web-sdk'; import { TracingInstrumentation } from '@grafana/faro-web-tracing'; const faro = initializeFaro({ url: 'http://alloy.local/collect', apiKey: 'api-key-app', instrumentations: [...getWebInstrumentations(), new TracingInstrumentation()], app: { name: 'example-frontend-app', version: '1.0.0', }, });
Просмотр данных мониторинга
Выполним запуск Frontend JavaScript приложения и перейдём в импортируемый нами ранее дашборд Grafana в котором мы увидим поступающие данные мониторинга:

Полные логи поступающие из Frontend приложения можно увидеть в Grafana перейдя в раздел Explore, далее выбрав источник Loki и выполнив запрос LogQL-{app="название_frontend_приложения"}

Поступающие трейсы в Tempo можно увидеть выбрав источник Tempo, далее в Query type необходимо выбрать TraceQL и ввести запрос- {rootServiceName="название_frontend_приложения"}

Дополнительная документация по использованию Grafana Faro:
