支付服务

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

支付服务源码

初始化 OpenTelemetry

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

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` 来启动您的应用程序。这可以在服务的 `Dockerfile` 的 `ENTRYPOINT` 命令中完成。

ENTRYPOINT [ "node", "--require", "./opentelemetry.js", "./index.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

Meter 可以使用 `@opentelemetry/api-metrics` 包创建。您可以像下面一样创建 Meter,然后使用创建的 Meter 来创建 Instrument。

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

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

Meter 和 Instrument 应该一直存在。这意味着您应该只获取一次 Meter 或 Instrument,然后尽可能重复使用它。

日志

待定

Baggage

此服务利用 OpenTelemetry Baggage 来检查请求是否为合成请求(来自负载生成器)。合成请求将不会被收费,这会通过 Span 属性来指示。 `charge.js` 文件负责实际的支付处理,其中包含用于检查 Baggage 的逻辑。

// check baggage for synthetic_request=true, and add charged attribute accordingly
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);
}

最后修改于 2025 年 3 月 4 日: [demo] 重命名 demo 服务 (#6438) (ae417344)