跳转到内容
Telemetry
浏览文档
指南更新于 2026年7月28日由 Telemetry 编辑团队和产品团队审核阅读约需 4 分钟

让编程智能体使用这篇文档

打开 Claude Code、Codex、Cursor 或其他编码代理的集中提示包,然后将其适应此处介绍的工作流程。

本页内容
  1. 演示证明了什么
  2. 先决条件
  3. 完整的程序
  4. 检查原始时间线
  5. 从同一个合约构建三个视图
  6. 可靠性
  7. 产品完成
  8. 成本和价值
  9. 生产变更

端到端 SaaS 可观测性演示

该演示将一组确定性的合成 SaaS 工作流事件发送到 Telemetry,并使用 SQL 查询它们。它故意设计得足够小,可以一次性检查,同时仍然连接可靠性、产品结果、后台工作和人工智能成本。

该示例不使用生产流量或客户数据。每次运行都有一个唯一的 run_id,因此它的查询可以隔离它创建的行。

演示证明了什么

一份广泛的事件合同可以回答几个问题:

  • 工作流程完成了吗?
  • 哪一步失败或重试?
  • 每个步骤花了多长时间?
  • 该工作流程产生的 AI 预估成本是多少?
  • 哪些帐户计划和版本受到影响?

该代码直接使用公共 HTTP 端点,因此事件、API 请求和 SQL 结果之间没有框架或 SDK 抽象。

先决条件

您需要 Node.js 20 或更高版本以及 Telemetry API 密钥。仅在将运行示例的 shell 中导出密钥:

export TELEMETRY_API_KEY="YOUR_API_KEY"

该存储库还将可运行源保留在 examples/saas-observability-demo 中。完整的程序如下所示,因此数据协定和查询在此页面上仍然可见。

完整的程序

将其另存为 demo.mjs

import { randomUUID } from "node:crypto";

const apiKey = process.env.TELEMETRY_API_KEY;
if (!apiKey) {
  throw new Error("TELEMETRY_API_KEY is required to run this demo");
}

const apiOrigin = process.env.TELEMETRY_API_ORIGIN || "https://api.telemetry.sh";
const runId = randomUUID();
const table = "saas_observability_demo";

const base = {
  run_id: runId,
  account_id: "synthetic_acme",
  plan: "growth",
  release: "demo-2026.07",
  region: "us-west",
};

const events = [
  {
    ...base,
    event_name: "checkout_started",
    workflow: "subscription_checkout",
    step: "checkout",
    outcome: "started",
    duration_ms: 18,
    retry_count: 0,
    estimated_cost_usd: 0,
  },
  {
    ...base,
    event_name: "payment_authorized",
    workflow: "subscription_checkout",
    step: "payment",
    outcome: "success",
    duration_ms: 284,
    retry_count: 0,
    estimated_cost_usd: 0,
  },
  {
    ...base,
    event_name: "invoice_job_completed",
    workflow: "subscription_checkout",
    step: "invoice_job",
    outcome: "success",
    duration_ms: 618,
    retry_count: 1,
    estimated_cost_usd: 0,
  },
  {
    ...base,
    event_name: "welcome_email_completed",
    workflow: "subscription_checkout",
    step: "welcome_email",
    outcome: "failed",
    duration_ms: 910,
    retry_count: 2,
    error_type: "provider_timeout",
    estimated_cost_usd: 0,
  },
  {
    ...base,
    event_name: "ai_summary_completed",
    workflow: "subscription_checkout",
    step: "ai_summary",
    outcome: "success",
    duration_ms: 742,
    retry_count: 0,
    model: "configured-demo-model",
    input_tokens: 820,
    output_tokens: 146,
    estimated_cost_usd: 0.0042,
  },
];

const ingestResponse = await fetch(`${apiOrigin}/log`, {
  method: "POST",
  headers: {
    Authorization: apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ table, data: events }),
});

if (!ingestResponse.ok) {
  throw new Error(
    `Ingest failed: ${ingestResponse.status} ${await ingestResponse.text()}`
  );
}

const sql = `
SELECT
  workflow,
  COUNT(*) AS event_count,
  SUM(CASE WHEN outcome = 'failed' THEN 1 ELSE 0 END) AS failed_steps,
  SUM(retry_count) AS retries,
  SUM(estimated_cost_usd) AS estimated_cost_usd,
  MAX(duration_ms) AS slowest_step_ms
FROM ${table}
WHERE run_id = '${runId}'
GROUP BY workflow
ORDER BY workflow
`;

const queryResponse = await fetch(`${apiOrigin}/query`, {
  method: "POST",
  headers: {
    Authorization: apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ query: sql, realtime: true, json: true }),
});

if (!queryResponse.ok) {
  throw new Error(
    `Query failed: ${queryResponse.status} ${await queryResponse.text()}`
  );
}

const result = await queryResponse.json();
console.log(JSON.stringify({ run_id: runId, rows: result.data }, null, 2));

运行它:

node demo.mjs

预期的形状是一个汇总行:

{
  "run_id": "generated-for-this-run",
  "rows": [
    {
      "workflow": "subscription_checkout",
      "event_count": 5,
      "failed_steps": 1,
      "retries": 3,
      "estimated_cost_usd": 0.0042,
      "slowest_step_ms": 910
    }
  ]
}

JSON 响应中的确切数字编码可能因查询结果序列化而异。以形义为契约。

检查原始时间线

聚合告诉您工作流程有一个失败的步骤。相关的时间线会告诉您哪个步骤失败了以及周围发生了什么:

SELECT
  timestamp_utc,
  event_name,
  step,
  outcome,
  duration_ms,
  retry_count,
  error_type
FROM saas_observability_demo
WHERE run_id = 'PASTE_RUN_ID'
ORDER BY timestamp_utc ASC;

run_id 的作用类似于工作流关联标识符。在实际应用程序中,使用在工作流边界创建的稳定标识符,并将其传递到 API 处理程序、队列有效负载、作业、Webhook 和 AI 调用。

从同一个合约构建三个视图

可靠性

releaseregion 绘制失败步骤和最大持续时间的图表。仅在定义最小量和团队期望的响应后发出告警。

产品完成

计算到达预期终端事件的不同工作流标识符。当一个工作流程可以发出多个步骤时,请勿将行计为已完成的工作流程。

成本和价值

对 AI 步骤求和 estimated_cost_usd 并将其加入或关联到后续结果,例如激活、接受的输出或成功的工作流程完成。将模型定价保留在版本化配置中,并将估算值与提供商发票进行核对。

生产变更

该演示更注重可见性而不是抽象性。生产实施应该:

  • 在实际操作边界而不是在演示数组中创建事件;
  • 使用有界模式并标准化路线、错误、计划和发布值;
  • 避免将不受信任的输入插入到 SQL 中;
  • 将 API 密钥保存在服务器端秘密存储中;
  • 批量或缓冲事件而不隐藏永久性故障;
  • 定义保留和删除要求;
  • 记录生产者独立演化时的模式版本;
  • 衡量事件传递本身是否失败。

使用 结构化日志记录 进行检测,使用 SQL 用于可观测性 进行分析模型,使用 连接SQL实验室 进行更大的六表数据集的可视化结果。

相关产品功能

记录稳定的事件名称、类型明确的字段,以及经过隐私审核的上下文。

内容责任与技术参考

Telemetry 编辑团队负责维护本文;产品团队审核功能行为、示例和适用范围。

查看编辑规范