支付服务

该服务负责处理订单的信用卡支付。如果信用卡无效或支付无法处理,它将返回一个错误。

支付服务源代码

初始化OpenTelemetry

建议使用一个初始化文件来require Node.js 应用程序,该文件会初始化 SDK 和自动仪表化。当在该模块的初始化器文件(opentelemetry.js)中初始化 OpenTelemetry Node.js SDK 时,您可以选择指定要利用的自动仪表化库,或者使用getNodeAutoInstrumentations()函数,该函数包括了大多数流行的框架。下面的示例初始化器文件(opentelemetry.js)包含了基于标准 OpenTelemetry 环境变量的代码,用于 OTLP 导出、资源属性和服务名称的初始化。然后,它在 SDK 初始化完成后使用require将您的应用程序引入./index.js以启动它。

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();

然后,您可以使用 opentelemetry.js 来启动您的应用程序。这可以在服务的 DockerfileENTRYPOINT 命令中完成。

ENTRYPOINT [ "node", "./opentelemetry.js" ]

追踪

为自动仪表化的 span 添加属性

在自动仪表化代码的执行过程中,您可以从上下文中获取当前 span。

const span = opentelemetry.trace.getActiveSpan();

使用 span 对象的 setAttributes 函数可以将属性添加到一个 span 中。在 chargeServiceHandler 函数中,作为匿名对象(map)的属性键/值对被添加到 span 中。

span.setAttributes({
  'app.payment.amount': parseFloat(`${amount.units}.${amount.nanos}`),
});

Span 异常和状态

您可以使用 span 对象的 recordException 函数创建一个具有已处理错误的完整堆栈跟踪的 span 事件。在记录异常时,还应相应地设置 span 的状态。您可以在 chargeServiceHandler 函数中看到这一点。

span.recordException(err);
span.setStatus({ code: opentelemetry.SpanStatusCode.ERROR });

指标

创建 Meter 和 Instrument

可以使用@opentelemetry/api-metrics包来创建 Meter。如下所示,您可以创建 Meter,然后使用创建的 Meter 创建 Instrument。

const { metrics } = require('@opentelemetry/api-metrics');

const meter = metrics.getMeter('paymentservice');
const transactionsCounter = meter.createCounter('app.payment.transactions');

Meters 和 Instruments 应该保持存在。这意味着,如果可能的话,应获取一次 Meter 或 Instrument,然后根据需要重复使用它。

日志

待定

Baggage

在此服务中,使用 OpenTelemetry Baggage 来检查请求是否是合成请求(来自负载生成器)。合成请求将不会收费,这在 span 属性中表示出来。负责实际支付处理的 charge.js 文件中,有检查 Baggage 的逻辑。

// 检查 Baggage 是否含有 synthetic_request=true,然后相应地添加 charged 属性
const baggage = propagation.getBaggage(context.active());
if (
  baggage &&
  baggage.getEntry('synthetic_request') &&
  baggage.getEntry('synthetic_request').value == 'true'
) {
  span.setAttribute('app.payment.charged', false);
} else {
  span.setAttribute('app.payment.charged', true);
}
最后修改 December 10, 2023: translate (a4350d6e)