Carly Richmond

同一枚硬币的两面:通过综合监控统一测试和监控

DevOps 旨在建立开发和运维之间的互补实践。了解 Playwright、@elastic/synthetics、GitHub Actions 和 Elastic Synthetics 如何在验证和监控用户体验方面团结开发和 SRE 团队。

13 分钟阅读
Two sides of the same coin: Uniting testing and monitoring with Synthetic Monitoring

从历史上看,软件开发和 SRE 一直在不同的文化视角和优先级下各自为营。DevOps 的目标是在软件开发和运维之间建立通用和互补的实践。然而,对于某些组织来说,真正的协作很少见,我们在建立有效的 DevOps 合作伙伴关系方面仍有很长的路要走。

除了文化挑战之外,这种脱节最常见的原因之一是使用不同的工具来实现相似的目标 — 例如,端到端 (e2e) 测试与综合监控

本博客分享了这些技术的概述。通过示例存储库 carlyrichmond/synthetics-replicator,我们还将展示 Playwright、@elastic/synthetics 和 GitHub Actions 如何与 Elastic Synthetics 和记录器结合,以团结开发和 SRE 团队,从而验证和监控托管在 Netlify 等提供商上的简单 Web 应用程序的用户体验。

Elastic 最近推出了综合监控,并且正如我们之前的博客中强调的那样,它可以完全取代 e2e 测试。围绕单个工具进行统一,以便尽早验证用户工作流程,这为重现用户问题以验证修复提供了通用语言。

综合监控与 e2e 测试

如果开发和运维工具之间存在冲突,则很难将它们的不同文化统一起来。考虑到这些方法的定义,可以发现它们实际上旨在实现相同的目标。

e2e 测试是一组重现用户路径的测试,包括点击、用户文本输入和导航。尽管许多人认为它是在测试软件应用程序各层的集成,但 e2e 测试模拟的是用户工作流程。同时,综合监控,特别是称为浏览器监控的子集,是一种应用程序性能监控实践,它模拟用户通过应用程序的路径。

这两种技术都模拟用户路径。如果我们使用跨越开发人员和运维分歧的工具,我们可以共同构建测试,这些测试还可以在我们的 Web 应用程序中提供生产监控。

创建用户旅程

当我们的应用程序中正在开发新的用户工作流程或实现关键目标的一组功能时,开发人员可以使用 @elastic/synthetics 来创建用户旅程。安装后,可以使用 init 实用程序生成初始项目框架,如下例所示。请注意,必须先安装 Node.js 才能使用此实用程序。

npm install -g @elastic/synthetics
npx @elastic/synthetics init synthetics-replicator-tests

在开始向导之前,请确保您具有 Elastic 集群信息,并在集群上设置了 Elastic Synthetics 集成。您将需要

  1. 必须在 Elastic Synthetics 应用程序中启用监控管理,如文档入门中的先决条件中所述。
  2. 如果使用 Elastic Cloud,则需要 Elastic Cloud 集群 Cloud ID。或者,如果您使用本地托管,则需要输入 Kibana 端点。
  3. 从您的集群生成的 API 密钥。在 Synthetics 应用程序设置中的“项目 API 密钥”选项卡下,有一个快捷方式可以生成此密钥,如文档中所述。

此向导将引导您完成并生成一个示例项目,其中包含配置和示例监控旅程,其结构类似于以下内容

对于 Web 开发人员来说,大多数元素(如 README 和 package.json 和锁定文件)都很熟悉。您的监控的主要配置在 synthetics.config.ts 中提供,如下所示。可以修改此配置以包括生产和开发特定的配置。这对于整合力量并重用相同的监控以进行 e2e 测试以及允许任何旅程用作 e2e 测试和生产监控至关重要。虽然本示例中没有,但如果希望从您自己的专用 Elastic 实例而不是从 Elastic 基础设施进行监控,则可以包含私有位置的详细信息。

import type { SyntheticsConfig } from "@elastic/synthetics";

export default (env) => {
  const config: SyntheticsConfig = {
    params: {
      url: "https://127.0.0.1:5173",
    },
    playwrightOptions: {
      ignoreHTTPSErrors: false,
    },
    /**
     * Configure global monitor settings
     */
    monitor: {
      schedule: 10,
      locations: ["united_kingdom"],
      privateLocations: [],
    },
    /**
     * Project monitors settings
     */
    project: {
      id: "synthetics-replicator-tests",
      url: "https://elastic-deployment:port",
      space: "default",
    },
  };
  if (env === "production") {
    config.params = { url: "https://synthetics-replicator.netlify.app/" };
  }
  return config;
};

编写您的第一个旅程

尽管上述配置适用于项目中的所有监控,但可以为给定的测试覆盖它。

import { journey, step, monitor, expect, before } from "@elastic/synthetics";

journey("Replicator Order Journey", ({ page, params }) => {
  // Only relevant for the push command to create
  // monitors in Kibana
  monitor.use({
    id: "synthetics-replicator-monitor",
    schedule: 10,
  });

  // journey steps go here
});

@elastic/synthetics 包装器公开了许多标准测试方法,例如 before 和 after 构造,允许在测试中设置和拆除典型属性,并支持许多常见的断言辅助方法。支持的 expect 方法的完整列表在文档中列出。Playwright 页面对象也会公开,这使我们能够执行 API 中提供的所有预期活动,例如查找页面元素和模拟用户事件(例如在以下示例中描述的点击)。

import { journey, step, monitor, expect, before } from "@elastic/synthetics";

journey("Replicator Order Journey", ({ page, params }) => {
  // monitor configuration goes here

  before(async () => {
    await page.goto(params.url);
  });

  step("assert home page loads", async () => {
    const header = await page.locator("h1");
    expect(await header.textContent()).toBe("Replicatr");
  });

  step("assert move to order page", async () => {
    const orderButton = await page.locator("data-testid=order-button");
    await orderButton.click();

    const url = page.url();
    expect(url).toContain("/order");

    const menuTiles = await page.locator("data-testid=menu-item-card");
    expect(await menuTiles.count()).toBeGreaterThan(2);
  });

  // other steps go here
});

正如您在上面的示例中看到的,它还公开了 journey 和 step 构造。此构造反映了行为驱动开发 (BDD) 的实践,即在测试中显示用户通过应用程序的旅程。

开发人员能够针对本地运行的应用程序执行测试,作为其功能开发的一部分,以查看用户工作流程中成功和失败的步骤。在下面的示例中,蓝色概述了顶部的本地服务器启动命令。进一步向下显示了红色的监视器执行命令。

正如您从每个旅程步骤旁边的绿色勾号中看到的那样,我们的每个测试都通过了。太棒了!

门控您的 CI 管道

在 CI 管道中使用监控的执行作为合并代码更改和上传新版本监控的闸门非常重要。我们的 GitHub Actions 工作流程中的每个作业将在本节和后续部分中讨论。

测试作业会启动测试实例并运行我们的用户旅程,以验证我们的更改,如下所示。此步骤应在拉取请求中运行以验证开发人员的更改,以及在推送时运行。

jobs:
  test:
    env:
      NODE_ENV: development
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm install
      - run: npm start &
      - run: "npm install @elastic/synthetics && SYNTHETICS_JUNIT_FILE='junit-synthetics.xml' npx @elastic/synthetics . --reporter=junit"
        working-directory: ./apps/synthetics-replicator-tests/journeys
      - name: Publish Unit Test Results
        uses: EnricoMi/publish-unit-test-result-action@v2
        if: always()
        with:
          junit_files: "**/junit-*.xml"
          check_name: Elastic Synthetics Tests

请注意,与我们本地计算机上的旅程执行不同,我们在执行 npx @elastic/synthetics 时使用了 --reporter=junit 选项,以便将我们通过的(或者令人遗憾的是有时会失败的)旅程的可见性提供给 CI 作业。

自动上传监控

为了确保最新的监控在 Elastic Uptime 中可用,建议以编程方式推送监控,作为 CI 工作流程的一部分,如下面的示例任务所示。我们的工作流程有一个第二个推送作业,如下所示,它依赖于成功执行将您的监控上传到集群的测试作业。请注意,此作业在我们的工作流程中配置为在推送时运行,以确保更改已得到验证,而不仅仅是在拉取请求中提出。

jobs:
  test:  push:
    env:
      NODE_ENV: production
      SYNTHETICS_API_KEY: ${{ secrets.SYNTHETICS_API_KEY }}
    needs: test
    defaults:
      run:
        working-directory: ./apps/synthetics-replicator-tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm install
      - run: npm run push

当您创建项目时,@elastic/synthetics init 向导会为您生成一个推送命令,该命令可以从项目文件夹中触发。这通过步骤和 working_directory 配置在下面显示。推送命令需要来自您的 Elastic 集群的 API 密钥,该密钥应作为机密存储在受信任的保管库中,并通过工作流程环境变量引用。在将更新的监控配置推送到 Elastic Synthetics 实例之前,监控必须先通过也非常重要,以防止破坏您的生产监控。与针对测试环境运行的 e2e 测试不同,损坏的监控会影响 SRE 活动,因此任何更改都需要进行验证。因此,建议通过 needs 选项将依赖项应用于测试步骤。

使用 Elastic Synthetics 进行监控

上传监控后,它们会定期为 SRE 团队提供检查点,以了解用户工作流程是否按预期运行 — 这不仅因为它们会按先前显示的为项目和单个测试配置的定期计划运行,还因为能够检查所有监控运行的状态并按需执行它们。

“监控概览”选项卡使我们可以立即查看所有已配置监控的状态,以及通过卡片省略号菜单手动运行监控的功能。

在“监控”屏幕中,我们还可以导航到单个监控执行的概览,以调查失败情况。

SRE 现在拥有的另一项监控超能力是这些监控与 SRE 已经用于仔细检查应用程序性能和可用性的熟悉工具(例如 APM、指标和日志)之间的集成。名为 “调查” 的菜单允许 SRE 在对潜在的故障或瓶颈进行调查时轻松导航。

在发现问题和自动收到潜在问题通知之间也需要取得平衡。已经熟悉为问题通知设置规则和阈值的 SRE 将很高兴知道浏览器监控也可以做到这一点。下面显示了编辑示例规则。

浏览器监控的状态不仅可以配置为考虑是否有任何单独或集体的监控多次出现故障(如上面的状态检查中所示),还可以通过查看给定时间段内通过检查的百分比来衡量整体可用性。SRE 不仅对以传统的生产管理方式对问题做出反应感兴趣,他们还希望提高应用程序的可用性。

记录用户工作流程

通过开发生命周期生成端到端测试的局限性在于,有时团队会遗漏一些事情,而之前的工具集是面向开发团队的。尽管使用了多学科团队来设计直观的产品,但用户可能会以意想不到的方式使用应用程序。此外,开发人员编写的监控程序只会涵盖那些预期的工作流程,并且只有当这些监控程序在生产环境中失败,或者在对它们应用异常检测时开始表现出不同行为时,才会发出警报。

当出现用户问题时,以与监控相同的格式重现该问题非常有用。利用 SRE 在生成用户旅程方面的经验也很重要,因为他们会凭直觉地考虑开发人员可能难以理解并专注于正常情况的失败案例。但是,并非所有 SRE 都具有使用 Playwright 和 @elastic/synthetics 编写这些旅程的经验或信心。

Video Thumbnail

欢迎使用 Elastic Synthetics Recorder!上面的视频演练了如何使用它来记录用户旅程中的步骤,并将其导出到 JavaScript 文件中,以便包含在您的监控项目中。这对于反馈到开发阶段和测试开发的修复程序以解决问题非常有用。除非我们齐心协力共同使用这些监控程序,否则无法实现这种方法。

尝试一下!

从 8.8 版本开始,@elastic/synthetics 和 Elastic Synthetics 应用程序已全面上市,而可靠的记录器仍处于 Beta 测试阶段。通过社区讨论论坛中的 Uptime 类别或通过 Slack 分享您通过合成监控来弥合开发人员和运营部门之间鸿沟的经验。

监控愉快!

最初发布于 2023 年 2 月 6 日;更新于 2023 年 5 月 23 日。

  1. 为什么要以及如何用合成监控取代端到端测试
  2. 正常运行时间和合成监控
  3. 编写浏览器监控脚本
  4. 使用 Synthetics Recorder
  5. Playwright
  6. GitHub Actions