前端

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

前端源码

服务端仪表化

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

const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const {
  OTLPTraceExporter,
} = require('@opentelemetry/exporter-trace-otlp-grpc');
const {
  OTLPMetricExporter,
} = require('@opentelemetry/exporter-metrics-otlp-grpc');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const {
  alibabaCloudEcsDetector,
} = require('@opentelemetry/resource-detector-alibaba-cloud');
const {
  awsEc2Detector,
  awsEksDetector,
} = require('@opentelemetry/resource-detector-aws');
const {
  containerDetector,
} = require('@opentelemetry/resource-detector-container');
const { gcpDetector } = require('@opentelemetry/resource-detector-gcp');
const {
  envDetector,
  hostDetector,
  osDetector,
  processDetector,
} = require('@opentelemetry/resources');

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new OTLPTraceExporter(),
  instrumentations: [
    getNodeAutoInstrumentations({
      // only instrument fs if it is part of another trace
      '@opentelemetry/instrumentation-fs': {
        requireParentSpan: true,
      },
    }),
  ],
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter(),
  }),
  resourceDetectors: [
    containerDetector,
    envDetector,
    hostDetector,
    osDetector,
    processDetector,
    alibabaCloudEcsDetector,
    awsEksDetector,
    awsEc2Detector,
    gcpDetector,
  ],
});

sdk.start();

使用--require命令行参数加载Node自带模块。可以在package.jsonscripts.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 });

创建新的span

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

  • root: true会创建一个新的追踪,将该span设置为根span。
  • links用于指定到其他span的链接(甚至在另一个追踪中),以便进行参考。
  • attributes是添加到span的键值对,通常用于应用程序上下文。
span = tracer.startSpan(`HTTP ${method}`, {
  root: true,
  kind: SpanKind.SERVER,
  links: [{ context: syntheticSpan.spanContext() }],
  attributes: {
    'app.synthetic_request': true,
    [SemanticAttributes.HTTP_TARGET]: target,
    [SemanticAttributes.HTTP_STATUS_CODE]: response.statusCode,
    [SemanticAttributes.HTTP_METHOD]: method,
    [SemanticAttributes.HTTP_USER_AGENT]: headers['user-agent'] || '',
    [SemanticAttributes.HTTP_URL]: `${headers.host}${url}`,
    [SemanticAttributes.HTTP_FLAVOR]: httpVersion,
  },
});

浏览器仪表化

前端提供的基于Web的用户界面也被用于浏览器仪表化。OpenTelemetry仪表化是作为Next.js App组件的一部分包含在pages/_app.tsx中的。在此处导入并初始化仪表化。

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

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

utils/telemetry/FrontendTracer.ts文件包含了初始化TracerProvider、建立OTLP导出、注册追踪上下文传播器和注册特定于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 { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } 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: new Resource({
      [SemanticResourceAttributes.SERVICE_NAME]:
        process.env.NEXT_PUBLIC_OTEL_SERVICE_NAME,
    }),
  });

  provider.addSpanProcessor(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来检查请求是否是合成的(来自负载生成器)。合成请求将强制创建一个新的追踪。新追踪的根span将包含许多与HTTP请求仪表化span相同的属性。

要确定Baggage项是否已设置,可以使用propagation API解析Baggage头,并使用baggage API获取或设置条目。

const baggage = propagation.getBaggage(context.active());
if (baggage?.getEntry("synthetic_request")?.value == "true") {...}
最后修改 December 10, 2023: translate (a4350d6e)