Backstage 部署监控指南:使用 OpenTelemetry 与 Analytics API 打造可观测的开发门户
2026/9/10 19:53:56 网站建设 项目流程

Backstage 部署监控指南:使用 OpenTelemetry 与 Analytics API 打造可观测的开发门户

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

本文是一份面向 Backstage 运维管理员的部署监控实战指南。生产环境中的 Backstage 需要可观测性来跟踪系统健康、诊断问题和理解使用模式,为此 Backstage 在后端提供了内建的 OpenTelemetry 支持(指标与追踪),在前端提供了事件驱动的 Analytics API。读完本文,你将掌握:如何为后端接入 OpenTelemetry 导出器(Prometheus 指标、OTLP 追踪)、如何利用内置健康检查端点配置 Kubernetes 探针、如何为前端接入第三方分析工具并理解其事件模型,以及如何利用结构化 JSON 日志接入日志聚合系统。

监控总览:两条可观测性主线

Backstage 的可观测性设计围绕两条主线展开:

  • 后端:通过 OpenTelemetry 上报指标(metrics)与追踪(traces),结合内置的健康检查端点(health check endpoints)与结构化 JSON 日志,覆盖系统的健康、性能与运行状态。
  • 前端:通过事件驱动的 Analytics API 追踪用户行为,帮助理解哪些插件使用最频繁,量化 Backstage 投资的回报(ROI),同时可配合 Sentry、CloudWatch RUM、Cloudflare RUM 等服务做客户端错误上报。

两条主线互补:后端指标回答"系统是否健康、是否高效",前端分析回答"用户如何使用系统"。下面分别展开。

后端监控:OpenTelemetry 接入

Backstage 使用 OpenTelemetry 上报指标与追踪。接入流程分为三步:安装 OpenTelemetry 依赖包、创建插桩(instrumentation)文件、在后端启动前加载该文件。完整的分步教程见 Setup OpenTelemetry 教程,下文直接给出可操作的完整流程。

安装依赖

packages/backend中安装 OpenTelemetry Node SDK 与自动插桩包:

yarn --cwd packages/backend add \ @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-prometheus \ @opentelemetry/exporter-trace-otlp-http

各包职责如下:

  • @opentelemetry/sdk-node:OpenTelemetry Node.js SDK,负责装配指标读取器(metric reader)与追踪导出器(trace exporter)。
  • @opentelemetry/auto-instrumentations-node:自动插桩库,为 Express 等被调用库中的代码自动创建 spans。
  • @opentelemetry/exporter-prometheus:Prometheus 指标导出器,默认在localhost:9464/metrics暴露指标。
  • @opentelemetry/exporter-trace-otlp-http:OTLP HTTP 追踪导出器,将 traces 通过 HTTP 发送到如 Jaeger 等目标。

从源码看,Backstage 的插件(如 catalog)本身就在使用 OpenTelemetry API 发送自定义 traces 和 metrics,例如 catalog-backend 的数据库指标实现 通过metrics.createObservableGauge(...)注册catalog_entities_countcatalog_registered_locations_countcatalog_relations_count等观测指标。auto-instrumentations-node则负责捕获框架层的自动插桩数据。

教程中使用 Prometheus 导出器做演示,你可以按需替换为其他导出器(例如参考 OTLP exporters 相关文档);追踪部分使用 JSON/HTTP 导出器、以 Jaeger 为理想目标,同样可替换为你需要的工具。

创建 instrumentation 文件

packages/backend/src目录下创建instrumentation.js

// 防止因 worker 线程导致重复运行 const { isMainThread } = require('node:worker_threads'); if (isMainThread) { const { NodeSDK } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations, } = require('@opentelemetry/auto-instrumentations-node'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); const { OTLPTraceExporter, } = require('@opentelemetry/exporter-trace-otlp-http'); // 默认在 localhost:9464/metrics 导出指标 const prometheusExporter = new PrometheusExporter(); // 将 traces 发送到 localhost:4318/v1/traces const otlpTraceExporter = new OTLPTraceExporter({ // 默认 Jaeger URL 追踪端点 url: 'http://localhost:4318/v1/traces', }); const sdk = new NodeSDK({ metricReader: prometheusExporter, traceExporter: otlpTraceExporter, instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); }

几点说明:

  • 使用isMainThread检查可以避免因 worker 线程(Backstage 后台任务可能使用)而多次初始化 SDK。
  • getNodeAutoInstrumentations()返回全部自动插桩项,实际部署时你很可能不需要全部,建议按需精简,只保留你真正用到的插桩。
  • 指标默认端口为9464,路径为/metrics;OTLP traces 默认端点为http://localhost:4318/v1/traces,可按你的 Jaeger/Collector 部署位置调整。

配置 Views 调整直方图桶

OpenTelemetry 默认的直方图桶以毫秒为单位,而 Catalog 处理流程产生的直方图指标以秒为单位。你可以通过 OpenTelemetry 的 Views 功能调整桶边界,使其更贴合实际数据分布。

统一调整所有直方图桶:

const prometheus = new PrometheusExporter(); const sdk = new NodeSDK({ metricReader: prometheus, views: [ new View({ instrumentName: 'catalog.test', aggregation: new ExplicitBucketHistogramAggregation([ 0.01, 0.1, 0.5, 1, 5, 10, 25, 50, 100, 500, 1000, ]), }), ], });

更精细的定向配置:

const prometheus = new PrometheusExporter(); const sdk = new NodeSDK({ metricReader: prometheus, views: [ new View({ instrumentName: 'catalog.test', aggregation: new ExplicitBucketHistogramAggregation([ 0, 0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60, 120, 300, 1000, ]), }), ], });

上述代码中的instrumentName: 'catalog.test'为演示名称,实际使用时应替换为你关心的具体指标名(如catalog.processing.duration)。桶边界的选择应覆盖你预期的处理时长分布,太小会导致高值全部落入最后一个桶,失去区分度。

本地开发配置

关键在于 NodeSDK 与自动插桩必须在导入任何库之前完成初始化,因此需要使用 Node.js 的--require标志(详见 Node.js CLI 文档)在应用启动前预加载插桩文件。

packages/backend/package.jsonscripts中加入--require标志:

"scripts": { "start": "backstage-cli package start --require ./src/instrumentation.js", ...

随后正常执行yarn start启动 Backstage,即可在http://localhost:9464/metrics看到指标输出。

常见问题排查

如果指标或追踪无法工作,OpenTelemetry 提供了诊断工具。先安装@opentelemetry/api

yarn --cwd packages/backend add @opentelemetry/api

然后在sdk.start()调用之前加入如下片段,开启调试日志:

const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api'); diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

这会输出 OpenTelemetry 的调试日志,帮助你定位问题。不建议在生产环境启用——DEBUG 级别的日志量非常大。

此外,OpenTelemetry 提供了大量 SDK 环境变量,可用于禁用或配置特定功能(如采样率、导出间隔等),部署时可按需调整。

生产环境配置(Docker)

生产环境使用 Docker 部署时,需要确保 instrumentation 文件被正确打入镜像并预先加载。

第一步,在.dockerignore中加入下面一行(在推荐的标准.dockerignore配置下,确保 Docker 构建不会忽略插桩文件):

!packages/backend/src/instrumentation.js

第二步,在Dockerfile中把instrumentation.js复制到工作目录根:

COPY --chown=${NOT_ROOT_USER}:${NOT_ROOT_USER} packages/backend/src/instrumentation.js ./

第三步,在 CMD 数组中加入指向该文件的--require标志:

# 修改前 CMD ["node", "packages/backend", "--config", "app-config.yaml"] # 修改后 CMD ["node", "--require", "./instrumentation.js", "packages/backend", "--config", "app-config.yaml"]

可用指标清单

以下是 Backstage 当前暴露的可用指标(实际可用指标取决于你安装的插件及其版本,下表来自本仓库的教程文档与插件源码):

指标名含义
catalog_entities_countCatalog 中的实体总数(带kind标签)
catalog_registered_locations_countCatalog 中已注册 location 的总数
catalog_relations_count实体间关系(relations)的总数
catalog.processed.entities.count已处理的实体数量
catalog.processing.duration执行完整处理流程所花时间
catalog.processors.duration执行 catalog processors 所花时间
catalog.processing.queue.delay从被调度处理到实际开始处理之间的延迟
catalog.stitched.entities.count已缝合(stitched)的实体数量
catalog.stitching.duration执行完整缝合流程所花时间
catalog.stitching.queue.length当前缝合队列中的实体数
catalog.stitching.queue.delay从被调度缝合到实际开始缝合之间的延迟
scaffolder.task.count任务运行次数(计数器)
scaffolder.task.duration一次任务运行的耗时(直方图)
scaffolder.step.count步骤运行次数(计数器)
scaffolder.step.duration单次步骤运行耗时(直方图)
backend_tasks.task.runs.count后台任务累计运行次数
backend_tasks.task.runs.duration后台任务运行耗时的直方图
backend_tasks.task.runs.started每个任务(taskId标签)最近一次启动的 Unix 时间戳(秒)Gauge
backend_tasks.task.runs.completed每个任务最近一次完成的 Unix 时间戳(秒)Gauge

这些指标是设置告警的重要依据,例如可以用catalog.processing.queue.delay监控处理积压,用scaffolder.task.duration监控异常的慢任务。

指标背后的源码实现
  • Catalog 指标定义在 catalog-backend 数据库指标模块:catalog_entities_countcatalog_registered_locations_countcatalog_relations_count同时以"Prometheus Gauge(已标记 DEPRECATED,建议改用 OpenTelemetry 指标)"和"OpenTelemetry ObservableGauge"两种形式注册。其中实体计数从final_entities表读取(而非体积大 20~30 倍的search表),并带有 30 秒 TTL 的单飞缓存来合并并发抓取查询,避免每次 scrape 对数据库发起重复的重型查询。实体计数还按kind维度打标签,查询时用数据库方言从entity_ref解析 kind(PostgreSQL 用split_part、MySQL 用substring_index、SQLite 用substr/instr),见 entityRefKindExpression。
  • Scaffolder 指标定义在 NunjucksWorkflowRunner 的 scaffoldingTracker:同样以 prom-client(已标记 DEPRECATED)和 OpenTelemetry 两种方式注册scaffolder.task.countscaffolder.task.durationscaffolder.step.countscaffolder.step.duration,其中 OpenTelemetry 版本带template/step/result标签,unit: 's'明确以秒为单位,与教程中"Catalog 处理直方图以秒为单位"的提示一致。prom-client 版本指标名使用下划线命名(如scaffolder_task_count),OpenTelemetry 版本使用点号命名(如scaffolder.task.count),二者是同一语义的双份实现。
  • 各插件通用的指标创建工具函数位于 catalog-backend util/metrics.ts 与 scaffolder-backend util/metrics.ts,均为"先查全局 register 是否已注册同名指标,已注册则复用、否则新建"的模式,保证指标幂等创建。

健康检查端点

Backstage 内置了健康检查端点,可用于 Kubernetes 或其他编排系统中的存活(liveness)与就绪(readiness)探针:

  • /.backstage/health/v1/readiness:当后端已准备好对外提供流量时返回 healthy。
  • /.backstage/health/v1/liveness:当后端进程存活时返回 healthy。

这两个端点在 createHealthRouter 中实现:readiness端点调用RootHealthService.getReadiness()liveness端点调用getLiveness(),二者都以对应 HTTP 状态码 + JSON payload 响应。源码还支持通过backend.health.headers配置为健康检查响应附加自定义头(例如供负载均衡器识别的标识),这在 K8s 探针与外部 LB 健康检查结合的场景下非常有用。

一个典型的 Kubernetes 探针配置示例:

livenessProbe: httpGet: path: /.backstage/health/v1/liveness port: backend readinessProbe: httpGet: path: /.backstage/health/v1/readiness port: backend

前端分析:Analytics API

Backstage 提供事件驱动的 Analytics API,用于追踪前端用户行为。它既给应用集成方提供了"在自选分析工具中收集和分析使用数据"的灵活性,也给插件开发者提供了"为关键用户交互插桩"的标准接口。完整说明见 Plugin Analytics 文档。

核心概念

  • Events(事件):至少由action(如click)和subject(如"被点击的东西")组成。
  • Attributes(属性):事件级别的附加维度数据(键值对)。例如用户点击跳转到的 URL 可表示为{ "to": "/a/page" }
  • Context(上下文):事件发生的更广背景,默认包含pluginIdextensionId

这种事件组合方式支持从多个粒度分析:既能回答"某个路由上被点击最多的是什么"这样的细粒度问题,也能回答"我的 Backstage 实例中哪个插件使用最多"这样的宏观问题。

支持的 Analytics 工具

Analytics 事件转发本质上是 AnalyticsApi 的一个具体实现,常见的集成已打包为插件提供:

分析工具支持状态
Google Analytics支持 ✅
Google Analytics 4支持 ✅
New Relic Browser社区 ✅
Matomo社区 ✅
Quantum Metric社区 ✅
Generic HTTP社区 ✅

本文档场景下,你需要重点关注的三个是Google Analytics 4、New Relic Browser 与 Matomo(前文 006-monitoring.md 明确列出的三个)。

关键事件

以下表格总结了各插件可能捕获的关键事件(取决于你安装了哪些插件):

ActionSubject其他说明
navigate被导航到的页面 URL路由位置变化时立即触发(若关联插件/路由数据不明确,则推迟到数据可知后、下一个事件或文档卸载前触发)。当前路由参数会作为 attributes 附带
click被点击链接的文本to属性表示点击跳转的 URL
create被创建软件的名称;若模板未要求name属性,则使用new {templateName}context 携带entityRef(模板 ref,如template:default/template-name);value表示运行模板节省的分钟数(基于模板的backstage.io/time-saved注解)
search任意搜索栏组件中输入的搜索词context 携带searchTypesvalue表示查询结果总数(使用权限框架时可能不可见)
discover被点击的搜索结果标题value为结果排名,同时提供to属性
not-found导致 404 页面的资源路径至少由 TechDocs 触发

编写自定义集成

事件转发实现为 Backstage 的 Utility API,只需提供单个captureEvent(event)方法。新版前端系统使用AnalyticsImplementationBlueprint

import { AnalyticsImplementationBlueprint } from '@backstage/plugin-app-react'; export const acmeAnalyticsImplementation = AnalyticsImplementationBlueprint.make({ name: 'acme', params: define => define({ deps: {}, factory() { return { captureEvent: event => { window._AcmeAnalyticsQ.push(event); }, }; }, }), });

更完整的实现通常会封装初始化逻辑并从配置读取参数(旧版前端系统使用createApiFactory(analyticsApiRef, ...),见 plugins/analytics.md 文档):

import { AnalyticsApi, AnalyticsEvent, configApiRef, } from '@backstage/frontend-plugin-api'; import { AnalyticsImplementationBlueprint } from '@backstage/plugin-app-react'; import { AcmeAnalytics } from 'acme-analytics'; class AcmeAnalyticsImpl implements AnalyticsApi { private constructor(accountId: number) { AcmeAnalytics.init(accountId); } static fromConfig(config) { const accountId = config.getString('app.analytics.acme.id'); return new AcmeAnalyticsImpl(accountId); } captureEvent(event: AnalyticsEvent) { const { action, ...rest } = event; AcmeAnalytics.send(action, rest); } } export const acmeAnalyticsImplementation = AnalyticsImplementationBlueprint.make({ name: 'acme', params: define => define({ deps: { configApi: configApiRef }, factory: ({ configApi }) => AcmeAnalyticsImpl.fromConfig(configApi), }), });

按社区惯例,此类集成包应命名为@backstage/analytics-module-[name],配置统一放在app.analytics.[name]键下。如果分析平台有一等公民的用户身份概念,可约定以identityApi作为依赖,并用identityApi.getBackstageIdentity()解析出的userEntityRef作为发送给平台的基础用户 ID。

捕获自定义事件

在组件中通过useAnalytics()钩子获取 tracker(来自@backstage/frontend-plugin-api),其captureEvent方法接收actionsubject参数:

import { useAnalytics } from '@backstage/frontend-plugin-api'; const analytics = useAnalytics(); analytics.captureEvent('deploy', serviceName);

捕获的事件应反映用户意图和插件专属的领域动作,而不是通用点击或 UI 生命周期事件。许多@backstage/ui组件(如LinkButtonLinkTabMenuItemTagTable行)会自动捕获click事件,因此通常不需要手动插桩导航类点击;如果默认事件不满足需求,可传入noTrackprop 关闭默认捕获,并在自己的点击处理器中调用captureEvent

附加属性与数值:第三个options参数可携带维度attributes和数值value

analytics.captureEvent('merge', pullRequestName, { value: pullRequestAgeInMinutes, attributes: { org, repo, }, });

对应捕获到的事件对象:

{ "action": "merge", "subject": "Name of Pull Request", "value": 60, "attributes": { "org": "some-org", "repo": "some-repo" } }

上下文提供:对于只在 React 树上层的元数据,使用<AnalyticsContext>包裹(context 可嵌套,沿 React 树向下合并,允许键被覆盖;核心自动附带的pluginIdextensionId始终存在):

import { AnalyticsContext, useAnalytics } from '@backstage/frontend-plugin-api'; const MyComponent = ({ value }) => { const analytics = useAnalytics(); const handleClick = () => analytics.captureEvent('check', value); return <SomeThing value={value} onClick={handleClick} />; }; const MyWrapper = () => { return ( <AnalyticsContext attributes={{ segment: 'xyz' }}> <MyComponent value={'Some Value'} /> </AnalyticsContext> ); };

事件命名建议:避免使用过于具体的action(例如用filter而非filterEntityTable,让extensionId自动携带EntityTable上下文);添加 attributes/context 时参考既有事件,保持键的意图、类型甚至内容一致(例如 Catalog 相关事件通常包含entityRef上下文键),以便跨插件聚合分析。

单元测试@backstage/frontend-test-utils提供MockAnalyticsApi,可在测试中配合TestApiProvider注入analyticsApiRef,用apiSpy.getEvents()断言捕获的事件内容(action、subject、attributes 等)。

前端错误上报

除了行为分析,还应考虑接入客户端错误上报服务(如 Sentry、CloudWatch RUM、Cloudflare RUM),用于捕获和诊断前端运行时错误。这是对 Analytics 的有力补充:分析回答"用户在做什么",错误上报回答"用户遇到了什么问题"。

日志:结构化 JSON 输出

Backstage 后端默认向 stdout 输出结构化 JSON 日志,包含servicepluginlevelmessage等字段,可直接被 Elasticsearch、Datadog、Splunk 等日志聚合工具解析。这意味着你无需编写额外的日志解析逻辑,只需将 stdout 采集到日志管道即可。

实际使用建议:

  • 在 Kubernetes 中,容器 stdout 会被 kubelet 自动收集到节点日志目录,配合 DaemonSet 日志采集器(如 Filebeat、Fluentd)即可汇入聚合平台。
  • 可基于level字段(如errorwarn)配置日志告警,与指标告警互为补充。
  • plugin字段可用于按插件维度分析错误分布,快速定位问题插件。

下一步:规模化监控

随着更多用户采用你的 Backstage 实例,监控数据会帮助你判断何时需要扩容——例如 API 响应时间上升、catalog.processing.duration显示 Catalog 处理落后、scaffolder 任务排队时间超出预期、用户反馈页面加载缓慢等信号。扩容前优先考虑水平扩展(增加副本),这比拆分后端更简单且能覆盖大多数增长场景。详见 Scaling your deployment 与 Scaling Backstage Deployments。

参考资源

  • 本指南出处:Golden Path 部署系列 · Monitoring your deployment
  • OpenTelemetry 完整接入教程:Setup OpenTelemetry
  • 前端分析完整文档:Plugin Analytics(新前端系统) 与 Plugin Analytics(旧文档)
  • 健康检查端点实现:createHealthRouter.ts
  • Catalog 指标实现:database/metrics.ts
  • Scaffolder 指标实现:NunjucksWorkflowRunner.ts

【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询