使用 Prometheus 监控 React 应用_应用程序

Prometheus 最初是为监控后端服务而设计的,因此用它来观察 React 应用程序并不常见。本文中,我们将介绍如何使用 Prometheus 在应用程序架构中使用单个监控工具来监控 React 应用程序。

监控Asserts UI

在 Asserts,我们一直在对自己的产品进行处理,并用它来监控我们的后端服务。

经过一番研究,我们发现可以帮助我们发布前端 Prometheus 指标的库已经存在。我们能够配置它们并将它们添加到我们的 react 应用程序中。

使用 prom-react 和发布自定义指标进行检测

prom-react 建立在 promjs 和 react-performance 库之上,并增加了将 React 应用程序包装在 MetricsProvider 中的能力,该 MetricsProvider 默认提供流量和延迟指标,如下所示:

const goldenMetrics: MetricDefinition[] = [
  {
    type: 'counter',
    name: GoldenMetrics.AppLoaded,
    description: 'Application loaded counter',
  },
  {
    type: 'counter',
    name: GoldenMetrics.AppUnloaded,
    description: 'Application unloaded counter',
  },
  {
    type: 'histogram',
    name: GoldenMetrics.PageNavigation,
    description: 'Total navigation duration between pages in seconds',
  },
  {
    type: 'histogram',
    name: GoldenMetrics.PageTimeToComplete,
    description: 'Section time to interactive in seconds',
  },
  {
    type: 'histogram',
    name: GoldenMetrics.PageTimeToUsable,
    description: 'Section time to usable in seconds',
  },
  {
    type: 'histogram',
    name: GoldenMetrics.PerformanceTime,
    description: 'Application performance load time in seconds',
  },
];

我们缺少另一个指标 - 测量ajax请求的持续时间,但prom-react允许我们添加自定义指标。

得到以下指标:

  • 应用程序加载和卸载
  • 页面之间的导航时间(按每个页面 URI)
  • 所有页面的应用程序性能加载时间(以秒为单位)(Load、DomContentLoaded、TimeToFirstByte、TimeToFirstPaint、TimeToFirstContentfulPaint)
  • 此外,我们还测量后端 AJAX 响应时间

github上的cabify提供了此用例的文档。

现在,让我们来看看我们在项目中集成 prom-react 时遇到了哪些“反应”问题。

Create-react-appreact-performance 和 .mjs 文件问题

安装 prom-react 后,react 应用程序(使用 CRA 的打字稿模板创建)崩溃并出现以下错误:

Failed to compile.

./node_modules/@shopify/react-performance/build/esm/performance-report.mjs
Can't import the named export 'Header' from non EcmaScript module (only default export is available)

发生这种情况是因为 prom-react 重新导出 react-performance,并且它包含文件。一个已知问题,即 CRA 在使用具有模块导出的包时崩溃。快速解决方案是 react-app-rewired,配置如下:.mjs.mjs

module.exports = function override(config) {
  config.module.rules.push({
    test: /\.mjs$/,
    include: /node_modules/,
    type: "javascript/auto"
  });

  return config;
}

config-overrides.js 文件

此外,更改脚本package.json

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
  },

改后

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
  },

就是这样!现在它可以毫无问题地编译。

监视 Ajax 请求

prom-react 的想法是拥有一个来自 promjs 的单一注册表并将其提供给所有 React 组件树,因此我们可以使用 hook 来定义阶段 ( 和 ) 更多信息可以在这里找到。我们的目标是测量 Ajax 请求的延迟,在这种情况下,我们需要能够使用相同的注册表从钩子调用方法。当然,我们可以对已经包含一些有关 Ajax 请求延迟的信息的阶段,但它并不精确,因为它还包含渲染时间。出于此类目的以及其他目的(例如,公开 Snackbar 以在 Axios 拦截器中使用通知程序),我们将 npm 库 react-outside-call 与此自定义指标配置一起使用。usePerformanceMarkStage.UsableStage.Complete.observeuseMetricsusePerformanceMark

import { MetricDefinition, useMetrics } from '@cabify/prom-react';
import { createCaller } from 'react-outside-call';

export const PROM_UI_REQUEST_SECONDS_COUNT: MetricDefinition = {
  type: 'histogram',
  name: 'prom_ui_request_seconds_count',
  description: 'A metric for UI request latency',
  buckets: [0.2, 0.5, 1, 2, 5, 10],
};

export const customPromMetrics: MetricDefinition[] = [
  PROM_UI_REQUEST_SECONDS_COUNT,
];

export const callConfig = createCaller({
  // eslint-disable-next-line react-hooks/rules-of-hooks
  metrics: () => useMetrics(),
});

使用 Axios 拦截器,我们测量请求/响应时间,并通过 观察这个指标。开始时间被放入请求标头中。callConfigreact-outside-call

import axios, { AxiosInstance } from 'axios';
import { callConfig, PROM_UI_REQUEST_SECONDS_COUNT } from './constants';

export const apiHttpService: AxiosInstance = axios.create({});

apiHttpService.interceptors.request.use((req) => {
  req.headers = {
    'request-startTime': performance.now().toString(),
  };
  return req;
});

apiHttpService.interceptors.response.use((res) => {
  const start = res.config.headers?.['request-startTime'];
  const end = performance.now();

  callConfig.call.metrics?.observe(
    PROM_UI_REQUEST_SECONDS_COUNT.name,
    {
      uri: res.config.url?.replace(/\?.*/, '') || 'unknown',
      method: res.config.method?.toUpperCase() || 'unknown',
      statusCode: res.status.toString(),
    },
    (end - start) / 1000,
  );

  return res;
});

将指标发布到 Prometheus

Prometheus 旨在抓取目标。库将指标发送到 configured for 。Prometheus 聚合网关可用于收集它们。现在,如果访问聚合网关的终端节点,将看到如下所示的指标列表:metricsAggregatorUrlMetricsProvider/metrics

# HELP prom_react_app_loaded Application loaded counter
# TYPE prom_react_app_loaded counter
prom_react_app_loaded{app_name="jarvis",status="failure"} 18
prom_react_app_loaded{app_name="jarvis",owner="asserts",status="success"} 25826

# HELP prom_react_app_unloaded Application unloaded counter
# TYPE prom_react_app_unloaded counter
prom_react_app_unloaded{app_name="jarvis",owner="asserts"} 1877

# HELP prom_react_navigation_duration_seconds Total navigation duration between pages in seconds
# TYPE prom_react_navigation_duration_seconds histogram
prom_react_navigation_duration_seconds_bucket{app_name="jarvis",navigation_type="full_page",owner="asserts",path="/assertions",le="1"} 8876

# HELP prom_react_performance_seconds Application performance load time in seconds
# TYPE prom_react_performance_seconds histogram
prom_react_performance_seconds_bucket{app_name="jarvis",event_type="dcl",owner="asserts",le="1"} 7856
prom_react_performance_seconds_bucket{app_name="jarvis",event_type="load",owner="asserts",le="1"} 7771
prom_react_performance_seconds_bucket{app_name="jarvis",event_type="ttfb",owner="asserts",le="1"} 11321
prom_react_performance_seconds_bucket{app_name="jarvis",event_type="ttfcp",owner="asserts",le="1"} 6562
prom_react_performance_seconds_bucket{app_name="jarvis",event_type="ttfp",owner="asserts",le="1"} 8114

# HELP prom_react_ttc_seconds Section time to interactive in seconds
# TYPE prom_react_ttc_seconds histogram
prom_react_ttc_seconds_bucket{app_name="jarvis",navigation_type="full_page",owner="asserts",path="/",le="1"} 8876

# HELP prom_react_ttu_seconds Section time to usable in seconds
# TYPE prom_react_ttu_seconds histogram
prom_react_ttu_seconds_bucket{app_name="jarvis",navigation_type="full_page",owner="asserts",path="/",le="1"} 8876

# HELP prom_ui_request_seconds_count A metric for UI request latency
# TYPE prom_ui_request_seconds_count histogram
prom_ui_request_seconds_bucket{app_name="jarvis",method="POST",owner="asserts",statusCode="200",uri="/api-server/v1/search/assertions",le="1"} 759

指标在 Prometheus 中后,您可以在 Prometheus UI 中开始运行 PromQL 查询或使用 Grafana Dashboards。

使用 Prometheus 监控 React 应用_应用程序_02

XHR 请求延迟的指标结果示例

可以通过 PromQL 和 Grafana 仪表板获得并与其他后端指标相关联。