You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为SvelteKit函数配置OpenTelemetry手动埋点并作为Trace首个Span

SvelteKit 中 OpenTelemetry 手动埋点解决方案

核心要点:区分客户端/服务端的 Tracer 获取方式

SvelteKit 的同构特性要求必须分开处理服务端和客户端的 OTel 初始化与 Tracer 获取逻辑,这是你之前导入出错和 Span 不显示的核心原因。


1. 服务端(+page.server.js/ts 或服务端加载函数)手动埋点

服务端复用已有的 NodeSDK,直接从 SDK 获取 Tracer,确保自定义 Span 作为 Trace 的第一个条目(根节点)。

示例代码:

// 假设你的 NodeSDK 初始化文件在 src/lib/otel/server.ts
import { tracer } from '$lib/otel/server';

export async function load() {
  // 创建根 Span
  const rootSpan = tracer.startSpan('getContactsAndUpdateStore', {
    kind: 1, // SpanKind.INTERNAL
    attributes: {
      'component': 'sveltekit-page-load',
      'page': '/contacts'
    }
  });

  try {
    // 包裹业务逻辑
    const contacts = await fetchContacts();
    // 执行更新 Store 的逻辑

    rootSpan.setStatus({ code: 0 }); // StatusCode.OK
    return { contacts };
  } catch (error) {
    rootSpan.setStatus({ 
      code: 2, // StatusCode.ERROR
      message: error instanceof Error ? error.message : 'Unknown error'
    });
    rootSpan.recordException(error);
    throw error;
  } finally {
    // 必须结束 Span,否则无法上报
    rootSpan.end();
  }
}

2. 客户端(+page.svelte 或组件)手动埋点

客户端需要单独初始化 Web SDK,不能直接使用服务端的 NodeSDK,同时要避免服务端渲染时导入客户端依赖。

第一步:客户端 OTel 初始化(src/lib/otel/client.ts)

import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
import { ZoneContextManager } from '@opentelemetry/context-zone';

let tracer;

// 仅在浏览器环境下初始化
if (typeof window !== 'undefined') {
  const provider = new WebTracerProvider();
  provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter({
    url: 'http://你的Tempo采集地址:4318/v1/traces'
  })));
  provider.register({
    contextManager: new ZoneContextManager()
  });

  registerInstrumentations({
    instrumentations: [new FetchInstrumentation()]
  });

  tracer = provider.getTracer('sveltekit-client');
}

export { tracer };

第二步:在 +page.svelte 中使用客户端 Tracer

<script>
  import { onMount } from 'svelte';
  let tracer;

  // 确保在客户端挂载后加载 Tracer
  onMount(async () => {
    const { tracer: clientTracer } = await import('$lib/otel/client');
    tracer = clientTracer;
  });

  async function getContactsAndUpdateStore() {
    if (!tracer) return;

    // 创建客户端根 Span
    const span = tracer.startSpan('getContactsAndUpdateStore', {
      kind: 1,
      attributes: { 'component': 'sveltekit-page-component' }
    });

    try {
      // 业务逻辑
      const res = await fetch('/api/contacts');
      const contacts = await res.json();
      // 更新 Store 操作

      span.setStatus({ code: 0 });
    } catch (error) {
      span.setStatus({ code: 2, message: error.message });
      span.recordException(error);
    } finally {
      span.end();
    }
  }
</script>

<button on:click={getContactsAndUpdateStore}>加载联系人</button>

3. 自定义 Span 不显示的关键排查点

  • 必须调用 span.end():未结束的 Span 不会被上报到 Tempo。
  • 上下文关联:如果需要让自动埋点的 Span 成为自定义 Span 的子节点,需在业务逻辑中传递上下文:
    import { context, trace } from '@opentelemetry/api';
    // 在根 Span 上下文下执行业务逻辑
    const contacts = await context.with(trace.setSpan(context.active(), rootSpan), () => fetchContacts());
    
  • 客户端初始化时机:通过 typeof window !== 'undefined' 确保仅在浏览器环境初始化,避免服务端渲染报错。
  • Exporter 配置检查:确认 Tempo 采集地址、端口正确,且服务端配置了允许客户端上报的 CORS 规则。

内容的提问来源于stack exchange,提问作者Voran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:37:46