前端

前端负责为用户提供 UI,以及 UI 或其他客户端使用的 API。该应用程序基于 Next.JS 构建,提供基于 React 的 Web UI 和 API 路由。

前端源代码

服务器端仪表化

建议在启动 Node.js 应用程序时使用 Node.js 的 `require` 模块来初始化 SDK 和自动仪表化。在初始化 OpenTelemetry Node.js SDK 时,您可以选择性地指定要使用的自动仪表化库,或者使用 `getNodeAutoInstrumentations()` 函数,该函数包含大多数流行的框架。`utils/telemetry/Instrumentation.js` 文件包含所有必需的代码,用于根据标准的 OpenTelemetry 环境变量 初始化 SDK 和自动仪表化,用于 OTLP 导出、资源属性和服务名称。

const FrontendTracer = async () => {
  const { ZoneContextManager } = await import('@opentelemetry/context-zone');

  let resource = resourceFromAttributes({
    [ATTR_SERVICE_NAME]: NEXT_PUBLIC_OTEL_SERVICE_NAME,
  });
  const detectedResources = detectResources({ detectors: [browserDetector] });
  resource = resource.merge(detectedResources);

  const provider = new WebTracerProvider({
    resource,
    spanProcessors: [
      new SessionIdProcessor(),
      new BatchSpanProcessor(
        new OTLPTraceExporter({
          url:
            NEXT_PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||
            'https://:4318/v1/traces',
        }),
        {
          scheduledDelayMillis: 500,
        },
      ),
    ],
  });

  const contextManager = new ZoneContextManager();

  provider.register({
    contextManager,
    propagator: new CompositePropagator({
      propagators: [
        new W3CBaggagePropagator(),
        new W3CTraceContextPropagator(),
      ],
    }),
  });

  registerInstrumentations({
    tracerProvider: provider,
    instrumentations: [
      getWebAutoInstrumentations({
        '@opentelemetry/instrumentation-fetch': {
          propagateTraceHeaderCorsUrls: /.*/,
          clearTimingResources: true,
          applyCustomAttributesOnSpan(span) {
            span.setAttribute('app.synthetic_request', IS_SYNTHETIC_REQUEST);
          },
        },
      }),
    ],
  });
};

Node.js 的 `require` 模块通过命令行参数 `--require` 加载。这可以在 `package.json` 的 `scripts.start` 部分完成,并使用 `npm start` 启动应用程序。

"scripts": {
  "start": "node --require ./Instrumentation.js server.js",
},

追踪

Span 异常和状态

您可以使用 span 对象的 `recordException` 函数来创建带有已处理错误的完整堆栈跟踪的 span 事件。在记录异常时,请务必相应地设置 span 的状态。您可以在 `utils/telemetry/InstrumentationMiddleware.ts` 文件中 `NextApiHandler` 函数的 `catch` 块中看到这一点。

span.recordException(error as Exception);
span.setStatus({ code: SpanStatusCode.ERROR });

创建新跨度

可以使用 `Tracer.startSpan("spanName", options)` 创建和启动新的 span。可以使用几个选项来指定 span 的创建方式。

  • `root: true` 将创建一个新的 trace,并将此 span 设置为根 span。
  • `links` 用于指定指向其他 span(即使在另一个 trace 中)的链接,这些链接应该被引用。
  • `attributes` 是添加到 span 的键/值对,通常用于应用程序上下文。
span = tracer.startSpan(`${method}`, {
  root: true,
  kind: SpanKind.SERVER,
  links: [{ context: syntheticSpan.spanContext() }],
  attributes: {
    'app.synthetic_request': true,
    [ATTR_HTTP_RESPONSE_STATUS_CODE]: response.statusCode,
    [ATTR_HTTP_REQUEST_METHOD]: method,
    [ATTR_USER_AGENT_ORIGINAL]: headers['user-agent'] || '',
    [ATTR_URL_PATH]: target,
    [ATTR_URL_FULL]: `${headers.host}${url}`,
    [ATTR_NETWORK_PROTOCOL_VERSION]: httpVersion,
  },
});

浏览器端仪表化

前端提供的基于 Web 的 UI 也为浏览器进行了仪表化。OpenTelemetry 仪表化已包含在 `pages/_app.tsx` 的 Next.js App 组件中。在此处导入并初始化了仪表化。

import FrontendTracer from '../utils/telemetry/FrontendTracer';

if (typeof window !== 'undefined') FrontendTracer();

`utils/telemetry/FrontendTracer.ts` 文件包含初始化 TracerProvider、建立 OTLP 导出、注册 trace context propagators 和注册特定于 Web 的自动仪表化库的代码。由于浏览器将数据发送到可能位于不同域的 OpenTelemetry Collector,因此还会相应地设置 CORS 标头。

作为更改的一部分,为了将 `synthetic_request` 属性标志传递给后端服务,`instrumentation-fetch` 库的自定义 span 属性逻辑中添加了 `applyCustomAttributesOnSpan` 配置函数,以便每个浏览器端 span 都包含它。

import {
  CompositePropagator,
  W3CBaggagePropagator,
  W3CTraceContextPropagator,
} from '@opentelemetry/core';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

const FrontendTracer = async () => {
  const { ZoneContextManager } = await import('@opentelemetry/context-zone');

  const provider = new WebTracerProvider({
    resource: resourceFromAttributes({
      [ATTR_SERVICE_NAME]: process.env.NEXT_PUBLIC_OTEL_SERVICE_NAME,
    }),
    spanProcessors: [new SimpleSpanProcessor(new OTLPTraceExporter())],
  });

  const contextManager = new ZoneContextManager();

  provider.register({
    contextManager,
    propagator: new CompositePropagator({
      propagators: [
        new W3CBaggagePropagator(),
        new W3CTraceContextPropagator(),
      ],
    }),
  });

  registerInstrumentations({
    tracerProvider: provider,
    instrumentations: [
      getWebAutoInstrumentations({
        '@opentelemetry/instrumentation-fetch': {
          propagateTraceHeaderCorsUrls: /.*/,
          clearTimingResources: true,
          applyCustomAttributesOnSpan(span) {
            span.setAttribute('app.synthetic_request', 'false');
          },
        },
      }),
    ],
  });
};

export default FrontendTracer;

指标

待定

日志

待定

Baggage

OpenTelemetry Baggage 在前端被利用,以检查请求是否是合成的(来自负载生成器)。合成请求将强制创建一个新的 trace。新 trace 的根 span 将包含许多与 HTTP 请求仪表化 span 相同的属性。

要确定是否设置了 Baggage 项,您可以利用 `propagation` API 来解析 Baggage 标头,并利用 `baggage` API 来获取或设置条目。

const baggage = propagation.getBaggage(context.active());
if (baggage?.getEntry("synthetic_request")?.value == "true") {...}

最后修改日期 2025 年 12 月 18 日: Update JS docs to stable semconv attribute names (#8676) (8dad29e2)