导出器

处理并导出你的遥测数据

将遥测数据发送到 OpenTelemetry Collector,以确保其被正确导出。 在生产环境中使用 Collector 是最佳实践。若要可视化你的遥测数据,可将其导出到后端系统,例如 JaegerZipkinPrometheus,或某个特定厂商的后端。

可用的导出器

镜像仓库中包含一份 JavaScript 可用导出器的列表

在所有导出器中,OpenTelemetry 协议 (OTLP) 导出器是以 OpenTelemetry 数据模型为基础设计的, 能够无信息丢失地输出 OTel 数据。此外,许多处理遥测数据的工具都支持 OTLP (例如 PrometheusJaeger 和大多数厂商),在你需要时为你提供高度的灵活性。 若要了解更多关于 OTLP 的信息,请参阅 OTLP 规范

本页面介绍了主要的 OpenTelemetry JavaScript 导出器以及如何进行配置。

OTLP

Collector 设置

为测试和验证你的 OTLP 导出器,你可以运行一个 Docker 容器形式的 Collector,将遥测数据直接输出到控制台。

在一个空目录下创建名为 collector-config.yaml 的文件,并添加以下内容:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318
exporters:
  debug:
    verbosity: detailed
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [debug]
    metrics:
      receivers: [otlp]
      exporters: [debug]
    logs:
      receivers: [otlp]
      exporters: [debug]

然后运行以下命令,在 Docker 容器中启动 Collector:

docker run -p 4317:4317 -p 4318:4318 --rm -v $(pwd)/collector-config.yaml:/etc/otelcol/config.yaml otel/opentelemetry-collector

现在,这个 Collector 已能通过 OTLP 接收遥测数据。 之后你可能需要配置 Collector,将遥测数据发送到你的可观测性后端。

依赖项

若你希望将遥测数据发送至 OTLP 端点(比如 OpenTelemetry 采集器JaegerPrometheus),你可以从三种不同的传输协议中选择一种来传输数据:

开始前,先安装相应的导出器包作为项目的依赖项:

npm install --save @opentelemetry/exporter-trace-otlp-proto \
  @opentelemetry/exporter-metrics-otlp-proto
npm install --save @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/exporter-metrics-otlp-http
npm install --save @opentelemetry/exporter-trace-otlp-grpc \
  @opentelemetry/exporter-metrics-otlp-grpc

Node.js 环境使用指南

接下来,配置导出器以指向 OTLP 端点。 例如,你可以更新入门指南中的 instrumentation.ts(如果使用 JavaScript 则为 instrumentation.js)文件, 如下所示,通过 OTLP(http/protobuf)导出链路和指标数据:

/*instrumentation.ts*/
import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new OTLPTraceExporter({
    // 可选 - 默认 URL 为 http://localhost:4318/v1/traces
    url: '<your-otlp-endpoint>/v1/traces',
    // 可选 - 每个请求要发送的自定义头信息,默认为空
    headers: {},
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: '<your-otlp-endpoint>/v1/metrics', // URL 是可选项并且可以省略,默认值为 http://localhost:4318/v1/metrics
      headers: {}, // 一个可选对象,包含了要随每个请求一同发送的自定义请求头。
    }),
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
/*instrumentation.js*/
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const {
  OTLPTraceExporter,
} = require('@opentelemetry/exporter-trace-otlp-proto');
const {
  OTLPMetricExporter,
} = require('@opentelemetry/exporter-metrics-otlp-proto');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new OTLPTraceExporter({
    // 可选 - 默认 URL 为 http://localhost:4318/v1/traces
    url: '<your-otlp-endpoint>/v1/traces',
    // 可选 - 每个请求要发送的自定义头信息,默认为空
    headers: {},
  }),
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({
      url: '<your-otlp-endpoint>/v1/metrics', // URL 是可选项并且可以省略,默认值为 http://localhost:4318/v1/metrics
      headers: {}, // 一个可选对象,包含了要随每个请求一同发送的自定义请求头。
      concurrencyLimit: 1, // 一个用于限制待处理请求数量的可选阈值。
    }),
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

浏览器环境使用指南

当你在基于浏览器的应用程序中使用 OTLP 导出器时,你需要注意以下几点:

  1. 不支持使用 gRPC 进行导出
  2. 你的网站的内容安全策略(CSP)可能会阻止遥测数据的导出操作。
  3. 跨域资源共享(CORS)响应头可能不允许发送导出数据
  4. 你可能需要将采集器暴露到公共互联网

你可以在下方找到选用合适导出器的操作指南,去配置内容安全策略(CSP)与跨域资源共享(CORS)响应头,以及暴露采集器时需采取的防范措施。

使用 OTLP 导出器结合 HTTP/JSON 或 HTTP/protobuf 协议

基于 gRPC 协议的 OpenTelemetry 采集器导出器仅适用于 Node.js, 因此你只能使用基于 HTTP/JSON 协议的 OpenTelemetry 采集器导出器基于 HTTP/protobuf 协议的 OpenTelemetry 采集器导出器

如果你使用的是基于 HTTP/JSON 协议的 OpenTelemetry 采集器导出器, 请确保导出器的接收端(采集器或可观测性后端)支持 http/json,并且你将数据导出到正确的端点,端口设置为 4318。

配置 CSP

如果你的网站使用了内容安全策略(CSP),请确保包含了 OTLP 端点的域名。 如果你的采集器端点是 https://collector.example.com:4318/v1/traces,请添加以下指令:

connect-src collector.example.com:4318/v1/traces

如果你的 CSP 未包含 OTLP 端点,你会看到一条错误消息,指出对端点的请求违反了 CSP 指令。

配置 CORS 响应头

如果你的网站和采集器托管在不同的域名下,你的浏览器可能会阻止向采集器发送请求。 你需要为跨域资源共享(CORS)配置特殊的响应头。

OpenTelemetry 采集器为基于 HTTP 协议的接收器提供了一项功能, 可自动添加所需的请求头,使接收器能够接收来自网页浏览器链路数据:

receivers:
  otlp:
    protocols:
      http:
        include_metadata: true
        cors:
          allowed_origins:
            - https://foo.bar.com
            - https://*.test.com
          allowed_headers:
            - Example-Header
          max_age: 7200

安全地暴露你的采集器

若要从 Web 应用接收遥测数据,你需要允许终端用户的浏览器向采集器发送数据。 若你的 Web 应用可从公共互联网访问,那么你也必须将采集器设置为对所有用户开放访问。

建议你不要直接暴露采集器,而是在其前端部署反向代理(如 NGINX、Apache HTTP 服务器等)。 反向代理可负责 SSL 卸载、配置正确的跨域资源共享(CORS)响应头,以及实现诸多针对 Web 应用的专属功能。

下面是流行的 NGINX Web 服务器的配置示例,供你参考使用:

server {
    listen 80 default_server;
    server_name _;
    location / {
        # Take care of preflight requests
        if ($request_method = 'OPTIONS') {
             add_header 'Access-Control-Max-Age' 1728000;
             add_header 'Access-Control-Allow-Origin' 'name.of.your.website.example.com' always;
             add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type' always;
             add_header 'Access-Control-Allow-Credentials' 'true' always;
             add_header 'Content-Type' 'text/plain charset=UTF-8';
             add_header 'Content-Length' 0;
             return 204;
        }

        add_header 'Access-Control-Allow-Origin' 'name.of.your.website.example.com' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type' always;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://collector:4318;
    }
}

控制台

要调试你的插桩代码,或在本地开发环境中查看数值,你可以使用将遥测数据写入控制台(标准输出)的导出器。

如果你遵循了入门指南手动插桩指南, 你已经安装了控制台导出器。

ConsoleSpanExporter 包含在 @opentelemetry/sdk-trace-node 包中,而 ConsoleMetricExporter 包含在 @opentelemetry/sdk-metrics 包中。

Jaeger

后端设置

Jaeger 原生支持 OTLP,用于接收链路数据。 你可以通过运行一个 Docker 容器来启动 Jaeger,其 UI 默认在端口 16686 上可访问,并在端口 4317 和 4318 上启用 OTLP:

docker run --rm \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 16686:16686 \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 9411:9411 \
  jaegertracing/all-in-one:latest

使用方法

现在,按照说明设置 OTLP 导出器

Prometheus

要将你的指标数据发送到 Prometheus, 你可以选择启用 Prometheus 的 OTLP 接收器并且使用 OTLP 导出器,或者使用 Prometheus 导出器,这是一种 MetricReader, 他启动一个 HTTP 服务器,根据请求收集指标并将数据序列化为 Prometheus 文本格式。

后端设置

你可以按照以下步骤在 Docker 容器中运行 Prometheus,并通过端口 9090 访问:

创建一个名为 prometheus.yml 的文件,并将以下内容写入文件:

scrape_configs:
  - job_name: dice-service
    scrape_interval: 5s
    static_configs:
      - targets: [host.docker.internal:9464]

使用以下命令在 Docker 容器中运行 Prometheus,UI 可通过端口 9090 访问:

docker run --rm -v ${PWD}/prometheus.yml:/prometheus/prometheus.yml -p 9090:9090 prom/prometheus --enable-feature=otlp-write-receive

Prometheus 依赖项

导出器包作为项目依赖安装到你的应用中:

npm install --save @opentelemetry/exporter-prometheus

将你的 OpenTelemetry 配置更新为使用该导出器,并将数据发送到 Prometheus 后端:

import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';

const sdk = new opentelemetry.NodeSDK({
  metricReader: new PrometheusExporter({
    port: 9464, // 可选 - 默认值为 9464
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const sdk = new opentelemetry.NodeSDK({
  metricReader: new PrometheusExporter({
    port: 9464, // 可选 - 默认值为 9464
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

通过上述配置,你可以在 http://localhost:9464/metrics 访问你的指标数据。 Prometheus 或 OpenTelemetry 采集器中的 Prometheus 接收器可以从该端点采集指标数据。

Zipkin

后端设置

你可以通过执行以下命令,在 Docker 容器中运行 Zipkin

docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin

Zipkin 依赖项

若要将链路数据发送至 Zipkin,你可以使用 ZipkinExporter 导出器。

安装导出器包作为项目依赖安装到你的应用中:

npm install --save @opentelemetry/exporter-zipkin

将你的 OpenTelemetry 配置更新为使用该导出器,并将数据发送到 Zipkin 后端:

import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new ZipkinExporter({}),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin');

const sdk = new opentelemetry.NodeSDK({
  traceExporter: new ZipkinExporter({}),
  instrumentations: [getNodeAutoInstrumentations()],
});

自定义导出器

最后,你还可以编写自己的导出器。有关更多信息,请参见 API 文档中的 SpanExporter 接口.

批量处理 Span 和日志记录

OpenTelemetry SDK 提供了一组默认的 Span 和日志记录处理器, 允许你选择按单条(simple)或按批量(batch)方式导出一个或多个 Span。 推荐使用批量处理,但如果你不想批量处理 Span 或日志记录,可以使用 simple 处理器,方法如下:

/*instrumentation.ts*/
import * as opentelemetry from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  spanProcessors: [new SimpleSpanProcessor(exporter)],
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
/*instrumentation.js*/
const opentelemetry = require('@opentelemetry/sdk-node');
const {
  getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');

const sdk = new opentelemetry.NodeSDK({
  spanProcessors: [new SimpleSpanProcessor(exporter)],
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();