Введение
Здравствуйте. В данной статье будет выполнено рассмотрение и установка инструмента 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: