前端
前端负责为用户提供 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") {...}