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