mcpField
O
otel-nextjs-style

otel-nextjs-style

github.com/superloglabs开发13374 次安装21 周前更新
代码仓库

关于 otel-nextjs-style

面向 Next.js 应用的 OpenTelemetry 编码规范技能,涵盖框架初始化、路由跨度、日志和 LLM 提供方埋点,并指导开发者避免重复记录提供方遥测数据。

主要功能

  1. 01Next.js 框架入口配置
  2. 02路由处理器跨度指引
  3. 03LLM 提供方埋点指引
  4. 04OTLP 日志配置
  5. 05配置与冒烟检查指引

适用场景

  1. 01在 instrumentation.ts 中初始化遥测
  2. 02为 TypeScript 路由添加业务跨度
  3. 03埋点支持的 LLM 提供方
  4. 04配置结构化 OTLP 日志

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/superloglabs/skills --skill otel-nextjs-style

安装后在 Claude Code 中输入/otel-nextjs-style确认已加载。

详细介绍

OTel Next.js 风格

对于 Next.js 应用,优先使用框架入口点。

// instrumentation.ts
import { registerOTel } from "@vercel/otel";

export function register() {
  registerOTel({
    serviceName: "mugline-web",
  });
}

除非代码库不是常规的 Next/Vercel 应用,或已有必须扩展的自定义 provider,否则不要将其替换为自定义 NodeSDK 引导代码。

对于 JavaScript/TypeScript LLM provider,优先使用 provider 插桩,而不是手动创建子 span。对于 Anthropic,在同一引导代码中添加 OpenInference,并保持调用点原生。此示例使用 @vercel/[email protected];如果已安装的类型是 v1,请改用单数形式的 logRecordProcessor。

import Anthropic from "@anthropic-ai/sdk";
import { AnthropicInstrumentation } from "@arizeai/openinference-instrumentation-anthropic";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
import { registerOTel } from "@vercel/otel";

const anthropicInstrumentation = new AnthropicInstrumentation({
  traceConfig: {
    hideInputs: true,
    hideOutputs: true,
  },
});

anthropicInstrumentation.manuallyInstrument(Anthropic);

export function register() {
  registerOTel({
    serviceName: "mugline-web",
    instrumentations: [anthropicInstrumentation],
    logRecordProcessors: [new BatchLogRecordProcessor(new OTLPLogExporter())],
  });
}

路由处理程序

在自动插桩无法覆盖的地方使用原生 OTel API。

import { withSpan } from "@superlog/otel-helpers";

const tracer = trace.getTracer("mugline.web");
const meter = metrics.getMeter("mugline.web");
const requests = meter.createCounter("mug.copy.generated");

export async function POST(request: Request) {
  const tenantId = request.headers.get("x-tenant-id") ?? "tenant_demo";
  return await withSpan("mug.copy.generate", async (span) => {
    span.setAttribute("tenant.id", tenantId);
    requests.add(1, { "tenant.id": tenantId, outcome: "success" });
    return Response.json({ ok: true });
  }, { tracer });
}

对于 TypeScript 路由处理程序,使用 @superlog/otel-helpers 的 withSpan 创建有界业务 span;如果 package.json 中尚未包含 @superlog/otel-helpers,则添加它。只要可以安装此包,就必须使用它。这样可以将 span 生命周期和错误处理逻辑从处理程序主体中移出,并避免产生大量缩进差异。除非无法添加此辅助工具,或 span 的生命周期确实跨越多个回调,否则不要将整个路由改写为 tracer.startActiveSpan(...) 加上 try / catch / finally。

如果路由中有 LLM 调用,且 OpenInference/provider 插桩支持该 SDK,则不要包装 provider 调用。保留 client.messages.create(...) / 等效调用,并将业务上下文添加到活动的产品 span 或结构化日志中。如果 OpenInference 已报告 provider/model/token 属性,则不要在路由级 span、日志或指标中重复这些属性。不要在路由处理程序中计算 LLM 成本;Superlog 会在 UI/查询层根据 OpenInference 的 provider/model/token 属性推算成本。 对于 Next.js/ESM 中的 Anthropic,将插桩实例和 manuallyInstrument(Anthropic) 调用保留在模块作用域中,确保它们只运行一次,且在路由代码运行之前执行。

@vercel/otel 的 logs 选项要与已安装的包/类型匹配: @vercel/[email protected] 使用单数形式的 logRecordProcessor,而 @vercel/[email protected] 使用复数形式的 logRecordProcessors。对于常规 Next.js/Vercel 应用,不要将 registerOTel(...) 放在 NEXT_RUNTIME 条件判断中;Next 会在适当的运行时调用 instrumentation.ts,而 @vercel/otel 会处理自身的运行时差异。

console.info 不是 OTLP 日志导出。如果没有现有的 logger bridge,请使用 @opentelemetry/api-logs 记录生产环境日志。删除会重复记录同一结构化 OTel 日志事件的现有 console.* 调用:

logger.emit({
  severityNumber: SeverityNumber.INFO,
  severityText: "INFO",
  body: "generated mug copy",
  attributes: {
    "tenant.id": tenantId,
    "gen_ai.provider.name": "anthropic",
    "gen_ai.request.model": model,
    "app.gen_ai.use_case": "web.mug_copy",
    outcome: "success",
  },
});

配置与冒烟测试

在 instrumentation.ts 中使用 otel-onboarding-style 提供的源码级公开 Superlog 配置模式,然后将这些常量显式传递给 registerOTel。公开项目令牌仅用于写入,应与端点一同放在设置代码块中,就像 PostHog 项目令牌或 Sentry DSN 一样。

const SUPERLOG_ENDPOINT = "https://intake.superlog.sh";
const SUPERLOG_PUBLIC_TOKEN = "sl_public_...";

// The token MUST be sent as the `x-api-key` header. Ingest only reads
// `x-api-key` or `Authorization: Bearer <token>`; any other header name 401s.
function superlogHeaders(token: string): Record<string, string> {
  return { "x-api-key": token };
}

registerOTel({
  serviceName: "mugline-web",
  traceExporter: new OTLPTraceExporter({
    url: `${SUPERLOG_ENDPOINT}/v1/traces`,
    headers: superlogHeaders(SUPERLOG_PUBLIC_TOKEN),
  }),
  // …same shape for log + metric exporters
});

冒烟检查应使用代码库中已有的工具,例如 npm run typecheck 或 npm run build,并在可行时发送真实的应用请求。不要编写脆弱的内联 Node 脚本来直接导入 TypeScript 源文件,也不要假定存在 ts-node,除非它已经安装。

评论

支持 Markdown