关于 otel-nextjs-style
面向 Next.js 应用的 OpenTelemetry 编码规范技能,涵盖框架初始化、路由跨度、日志和 LLM 提供方埋点,并指导开发者避免重复记录提供方遥测数据。
主要功能
- 01Next.js 框架入口配置
- 02路由处理器跨度指引
- 03LLM 提供方埋点指引
- 04OTLP 日志配置
- 05配置与冒烟检查指引
适用场景
- 01在 instrumentation.ts 中初始化遥测
- 02为 TypeScript 路由添加业务跨度
- 03埋点支持的 LLM 提供方
- 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,除非它已经安装。