可观测性导出器
可观测性导出器会将网关用量事件发送到用于链路追踪、日志记录、存储或记账的目标。本指南将介绍如何通过 AISIX Cloud 或开源 AISIX 网关配置 OTLP/HTTP 导出器,并说明目标选择、内容采集和投递行为。
准备工作
请先准备以下内容:
- 以下任一配置路径:
- AISIX Cloud,其中包含一个环境、已关联的网关和具备写入权限的 Admin Token。对于 On-Premises,请按照 AISIX Cloud 快速入门操作。如需申请 Hybrid Cloud 访问权限,请联系 API7。
- 加载声明式
resources.yaml文件的开源 AISIX 网关。
- 计划使用的导出器对应的遥测目标。
- 用于验证投递的可用模型别名和调用方 API Key。
导出网关源地址(不含末尾斜杠或端点路径),以及验证所用的请求参数:
export AISIX_PROXY="YOUR_AISIX_GATEWAY_ORIGIN"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export MODEL_ALIAS="YOUR_MODEL_ALIAS"
在开源 AISIX 网关快速入门中,AISIX_PROXY 为 http://127.0.0.1:3000。其他部署方式请使用客户端访问网关的地址。
对于 AISIX Cloud 示例,请导出 Admin API 基础 URL、Admin Token 和环境 ID:
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_BASE_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
AISIX_CP 包含 /api,末尾不含斜杠。本地 On-Premises 快速入门使用 http://localhost:8080/api;其他部署方式请使用可访问的控制面 Admin API URL。
选择导出器类型
两种配置路径都支持所有导出器类型。AISIX Cloud API 请求和资源文件条目通过 kind 值选择类型,控制台则显示同一底层类型对应的标签:
kind 值 | 控制台标签 | 适用场景 |
|---|---|---|
otlp_http | OTLP/HTTP | 已经通过 OTLP/HTTP 收集器或厂商端点收集链路。 |
object_store | Object storage | 希望将批量 NDJSON 请求事件写入 Amazon S3、S3 兼容存储、Google Cloud Storage 或 Azure Blob。 |
datadog | Datadog | 使用 Datadog Logs HTTP 接收端。 |
aliyun_sls | Alibaba Cloud SLS | 使用阿里云日志服务作为日志目标。 |
网关会将遥测直接发送到所选目标。
配置 OTLP 导出器
设置示例使用的收集器端点和授权请求头:
# 请替换为实际值
export OTLP_ENDPOINT="https://collector.example.com/v1/traces"
export OTLP_AUTH_HEADER="Bearer YOUR_COLLECTOR_TOKEN"
网关进程必须能够访问该端点。如果接收端与网关进程位于同一主机,可以使用 http://localhost:4318/v1/traces;容器化网关则需要使用接收端在容器网络或宿主机上的地址。如果接收端不要求认证,请从导出器中移除 headers 块。
AISIX Cloud
创建导出器并获取其 ID:
EXPORTER_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/observability_exporters" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-otlp",
"kind": "otlp_http",
"endpoint": "'"${OTLP_ENDPOINT}"'",
"headers": {
"Authorization": "'"${OTLP_AUTH_HEADER}"'"
},
"sample_rate": 1
}' | jq -r '.observability_exporter.id')
❶ 只有当 OTLP 目标要求时才设置静态请求头。请求头值会加密存储,并且读取操作绝不会返回这些值。
❷ sample_rate: 1 可以让投递检查得到确定的结果。它等同于省略该字段,即导出每个请求链路。验证完成后,如需减少跨度数量,可以降低该值。
获取导出器,确认存储的配置:
curl -sS "$AISIX_CP/environments/$ENV_ID/observability_exporters/$EXPORTER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN"
你应该会看到类似下面的响应。读取操作通过 header_keys 暴露已配置的请求头名称,并通过 headers_set 确认已存储请求头值;但绝不会返回请求头值本身。
{
"observability_exporter": {
"id": "b46a9f5d-6a4d-4bb1-ae2c-4ab1b22f5e80",
"env_id": "0f2f6a1e-9d33-4a8f-9a6e-2a7b6a9c1d2e",
"name": "prod-otlp",
"enabled": true,
"kind": "otlp_http",
"endpoint": "https://collector.example.com/v1/traces",
"header_keys": ["Authorization"],
"headers_set": true,
"sample_rate": 1,
"created_at": "2026-07-22T08:30:00Z",
"updated_at": "2026-07-22T08:30:00Z"
}
}
保存 $EXPORTER_ID,以便后续更新或删除导出器。导出器默认启用。设置 enabled: false 可在不发送遥测的情况下保存资源。
开源 AISIX 网关
将以下导出器添加到完整资源文件的 observability_exporters 中。使用环境变量插值可以避免将收集器 Token 写入文件:
observability_exporters:
- name: prod-otlp
kind: otlp_http
endpoint: ${OTLP_ENDPOINT}
headers:
Authorization: ${OTLP_AUTH_HEADER}
sample_rate: 1
验证组装后的完整文件:
aisix validate --resources resources.yaml
在进程环境中设置 OTLP_ENDPOINT 和 OTLP_AUTH_HEADER,然后启动或重启网关。只有当这些变量已经可用于运行中的进程时,才重新加载网关。导出器默认启用;添加 enabled: false 可保留条目但不发送遥测。
验证 OTLP 投递
保存导出器只能确认 AISIX 接受了配置。要验证上面配置的 OTLP 导出器,请获取 AISIX 返回的请求 ID,在目标端查找该 ID,并检查网关的投递信号。如果正在检查的现有 OTLP 导出器的 sample_rate 小于 1,请暂时将采样率设为 1,避免该请求被采样丢弃。
通过一个可用的模型别名发送成功请求,并获取 AISIX 返回的 ID。无论 AISIX 接受调用方提供的 ID,还是自行生成 ID,这种方式都能取得准确结果:
export EXPORTER_NAME="prod-otlp"
if TEST_REQUEST_ID=$(
set -o pipefail
curl -fsS -D - -o /dev/null \
-X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer $AISIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${MODEL_ALIAS}"'",
"messages": [{"role": "user", "content": "Reply with: exporter check"}]
}' \
| awk 'tolower($1) == "x-aisix-request-id:" { id = $2; sub(/\r$/, "", id) } END { print id }'
) && test -n "$TEST_REQUEST_ID"; then
export TEST_REQUEST_ID
printf 'request ID: %s\n' "$TEST_REQUEST_ID"
else
unset TEST_REQUEST_ID
printf 'verification request failed or returned no request ID\n' >&2
false
fi
等待导出器发送该批次,然后在 OTLP 后端查找 aisix.request_id 属性等于 $TEST_REQUEST_ID 的跨度。找到该跨度即可确认端到端投递:网关已加载导出器,在需要时完成目标端认证,且目标端已接受该批次。
在 AISIX Cloud 中,环境的 Observability 视图通过导出器行显示投递是否健康,以及在线网关已发送的批次数。也可以通过 Admin API 查看相同的逐网关心跳数据:
curl -sS "$AISIX_CP/environments/$ENV_ID/dp_nodes" \
-H "Authorization: Bearer $AISIX_TOKEN" \
| jq --arg exporter "$EXPORTER_NAME" \
'[.data[] | select(.status != "offline") | .exporter_health[]? | select(.name == $exporter)]'
下次心跳后,至少一个在线网关应报告大于零的 delivered_batches 和 last_error: null。网关重启或导出器配置变更时,计数器会重置。非空的 last_error 表示当前投递失败。后续成功投递会清除 last_error,但历史字段 failed_batches 和 last_failure_unix 仍会保留数值。
使用开源 AISIX 网关时,请在目标端确认成功。如果记录未到达,请在网关日志中检查 sink delivery failed; retrying 或 sink delivery dropped after retries。
了解 OTLP 链路结构
对于每个产生 OTLP 遥测数据的请求,AISIX 会导出一个链路层级,而不是为每个用量事件导出彼此无关的跨度。模型请求到达上游时,层级如下:
| 跨度 | OTLP 类型 | 范围 |
|---|---|---|
| 入站请求 | SERVER | 覆盖请求从到达开始,直到响应完成或调用方断开连接。有效的入站 traceparent 会成为此跨度的远程父级。 |
| 逻辑操作 | CLIENT | 覆盖网关执行的上游操作,包括所有重试和故障转移尝试。它是 SERVER 跨度的子级。 |
| 上游尝试 | CLIENT | 表示一次服务提供方分发。每次尝试都是逻辑操作的子级,并携带 aisix.attempt_index。 |
因此,重试和故障转移会显示为同一逻辑操作下的同级尝试跨度。对于每个用量事件,AISIX 会把完整属性和捕获内容放在当前最具体的跨度上:优先放在尝试跨度,其次放在逻辑操作跨度,最后放在 SERVER 跨度。其他跨度仅携带关联该层级所需的字段,不会重复整个事件。
并非每个请求都包含所有三个层级:
- 缓存命中、输入安全护栏阻断或其他分发前结果只有 SERVER 跨度,因为 AISIX 没有调用上游。
- 不采用逐次尝试追踪的 MCP、A2A、Realtime、任务和透传调用包含 SERVER 跨度,以及一个表示上游操作的 CLIENT 跨度。
统计导出链路时,请根据跨度类型和父子关系,而不要只根据跨度名称。筛选 SERVER 跨度可以统计已采样的请求链路。sample_rate 小于 1 时,未被选中的请求不会出现。部分身份认证和格式错误输入路径会在用量事件或 OTLP 跨度产生前拒绝请求,因此 SERVER 跨度不能完整表示入站请求数。网关请求量请使用请求指标。分析单次模型尝试时,请使用携带 aisix.attempt_index 的 CLIENT 跨度。
延续入站 W3C 链路
请求中恰好包含一个有效的 traceparent 时,AISIX 会延续该链路,并让自己的 SERVER 跨度成为调用方跨度的子级。取值格式错误或存在多个 traceparent 时,AISIX 会忽略它们并启动本地链路,而不会拒绝请求。通过网关字符和长度检查的配套 tracestate 会记录在 SERVER 跨度上。
除非 forward_client_headers 精确点名,否则 AISIX 不会把调用方的 traceparent 或 tracestate 转发给模型服务提供方、透传目标、MCP 服务器或 A2A Agent;通配符模式永远不会匹配到它们。默认情况下,该上下文只用于建立调用方到网关的关系。转发边界参见上游请求头。
配置其他导出器
当遥测需要发送到对象存储或日志服务,而不是 OTLP 链路后端时,请使用其他导出器类型。使用 AISIX Cloud 时,将以下对象之一作为 POST $AISIX_CP/environments/$ENV_ID/observability_exporters 的请求体。
对象存储
对于对象存储,请选择存储服务提供方、存储桶和对象键前缀。默认认证模式使用由网关解析的凭证引用:
{
"name": "request-events-s3",
"kind": "object_store",
"provider": "s3",
"bucket": "acme-aisix-events",
"prefix": "ai-gateway",
"region": "us-east-1",
"credential_ref": "acme_s3"
}
对象存储支持 Amazon S3、Google Cloud Storage、Azure Blob 和 S3 兼容目标。只有当网关运行时带有可写入存储桶的附加身份时,才对 S3 或 GCS 使用云身份。对于 Azure Blob,以及要求静态凭证的 S3 兼容目标,请使用 credential_ref。
对于 MinIO、Cloudflare R2 或阿里云 OSS 等 S3 兼容目标,请显式设置目标端点。未设置端点时,S3 导出器会使用原生 AWS S3 端点。
阿里云 SLS
配置端点主机、项目、日志库和凭证引用:
{
"name": "request-events-sls",
"kind": "aliyun_sls",
"endpoint": "ap-southeast-3.log.aliyuncs.com",
"project": "acme-observability",
"logstore": "ai-gateway",
"credential_ref": "acme_sls"
}
Datadog
配置 Datadog 站点、服务名称、标签和凭证引用:
{
"name": "request-events-datadog",
"kind": "datadog",
"site": "datadoghq.com",
"service": "ai-gateway",
"tags": ["team:platform", "tier:prod"],
"credential_ref": "acme_datadog"
}
对于资源文件路径,请将以下条目添加到 observability_exporters:
observability_exporters:
- name: request-events-s3
kind: object_store
provider: s3
bucket: acme-aisix-events
prefix: ai-gateway
region: us-east-1
credential_ref: acme_s3
- name: request-events-sls
kind: aliyun_sls
endpoint: ap-southeast-3.log.aliyuncs.com
project: acme-observability
logstore: ai-gateway
credential_ref: acme_sls
- name: request-events-datadog
kind: datadog
site: datadoghq.com
service: ai-gateway
tags: ["team:platform", "tier:prod"]
credential_ref: acme_datadog
只保留实际使用的目标,然后按照 OTLP 示例所述验证资源文件并启动或重新加载网关。使用与 OTLP 相同的请求 ID 方法验证这些导出器:在对象存储和 SLS 记录中按 request_id 查找,在 Datadog 日志中按 aisix.request_id 查找。Snowflake 指南介绍了如何直接检查对象存储输出。
SLS、Datadog 和对象存储导出器通过凭证引用或云身份,让目标凭证不进入导出器资源。网关发送遥测时会在本地解析这些凭证。
配置内容采集
导出器默认包含请求 状态、Token 计数、模型和服务提供方标识、请求 ID、结束原因和时间信息,但不包含提示词和响应正文。OTLP/HTTP、SLS 和 Datadog 导出器可以选择启用完整内容采集。
启用完整内容采集
创建导出器时添加 content_mode 和 content_max_bytes。在 AISIX Cloud 中,可以使用相同字段修补现有导出器:
curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/observability_exporters/$EXPORTER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content_mode": "full",
"content_max_bytes": 131072
}'
在控制台中,将导出器表单的 Content mode 设置为 Full,然后调整 Max content bytes。
对于资源文件路径,请将这些字段添加到导出器条目中,然后验证并重新加载文件:
observability_exporters:
- name: prod-otlp
kind: otlp_http
endpoint: ${OTLP_ENDPOINT}
headers:
Authorization: ${OTLP_AUTH_HEADER}
content_mode: full
content_max_bytes: 131072
只有当目标已获准接收最终用户提示词和响应文本时,才使用完整内容采集。AISIX 会根据配置的字节上限分别截断采集到的提示词和响应字段。
了解截断记录
有效 JSON 超过 content_max_bytes 时,AISIX 会先按结构缩减,使导出字段仍为有效 JSON。如果缩减后仍超过上限,则回退到 UTF-8 安全的字节截断。采集的提示词是序列化后的请求体,遵循同样规则。
| 内容 | 截断行为 |
|---|---|
| 长字符串 | 保留前缀,并追加 ...[aisix: truncated, N bytes total] 行内标记。 |
| Base64 数据 URI | 用包含原始大小的占位符替换编码数据。 |
| 长数组 | 保留首尾样本,并插入 {"_aisix_truncated": true, "omitted_items": N} 元素,其中 N 统计全部省略项。 |
| 非 JSON 内容,或结构缩减后仍放不下的 JSON | 在 UTF-8 字符边界处截断。 |
发生截断时,OTLP 记录包含 aisix.content_truncated: true,Datadog 和 SLS 记录包含 content_truncated: true。
采集透传内容
对于成功中继的透传路由流量,完整内容采集会将请求体记录为字符串,并遵循导出器的内容上限和 JSON 结构感知截断规则。对于缓冲响应,响应符合受支持的提取结构时会记录提取出的文本,否则将响应体记录为文本。对于流式响应,会记录累积的提取文本;不透明数据负载则保留为文本。
采集失败请求
完整内容采集适用于下表汇总的受支持 AI 代理端点类型。A2A 采集记录的是消息内容,而不是 JSON-RPC 信封。完整内容采集不适用于 MCP、Realtime、任务或批处理遥测。透传请求如果在身份认证、授权、输入安全护栏或限流期间被拒绝,则不包含采集内容。
在 /v1/chat/completions、/v1/messages 和 /v1/responses 上,请求解析后产生用量事件的失败会把请求体记录到 prompt 字段,但 401 和 403 响应除外。这包括输入安全护栏阻断(422)、除 401 和 403 之外的上游失败,以及解析后的校验失败(例如 messages 数组为空)。执行数据脱敏时,AISIX 采集脱敏后的请求体;格式错误的 JSON 会在创建用量事件前被拒绝,因此不会采集。
还应注意以下边界:
- 调用方认证失败会在创建用量事件前被拒绝。
- 所有路由目标都失败时,最后一次尝试的记录携带提示词。
- 响应侧安全护栏阻断不会采集被阻断的输出。
这些边界既避免导出被拒绝的凭证和阻断输出,也保留调查其它失败所需的请求上下文。
查看各端点采集的内容
| 端点类型 | 采集的内容 |
|---|---|
| 文本生成 | 响应文本。 |
| A2A | message/send 和 message/stream 上,请求消息与回复消息里文本部分的内容。文件部分、数据部分和 JSON-RPC 信封不会被采集。 |
| Embeddings、Rerank 和图片生成 | 完整响应 JSON。 |
| 音频转录 | 返回的转录文本。上传音频不会被采集;其 SHA-256 校验和会与请求文本字段一起记录。 |
| 文本转语音 | 不采集二进制语音响应。 |
导出遥测中的模型字段
当调用方请求的模型别 名与处理某次尝试的模型不同时,用量遥测会同时记录两者。这对路由和合议流量很重要,因为一个面向调用方的别名可能解析为多个目标模型调用。
不同目标会以各自的遥测格式呈现这些值。OTLP 链路使用以下字段:
gen_ai.request.model包含调用方请求的别名。gen_ai.response.model包含服务提供方上报的具体响应模型版本。aisix.model_id标识解析后的模型资源。
网关协议跨度
A2A 或 MCP 调用不是模型推理,因此不会被编码成模型推理。A2A 导出为 invoke_agent <agent>,MCP 导出为 execute_tool <tool>,遵循 OpenTelemetry 生成式 AI 语义约定,并携带各自协议的细节:
- A2A:
gen_ai.agent.name、gen_ai.conversation.id(即 A2A 的上下文),以及aisix.a2a.operation、aisix.a2a.method、aisix.a2a.protocol_version、aisix.a2a.task_id、aisix.a2a.task_state、aisix.a2a.stream_event_count。 - MCP:
gen_ai.tool.name和aisix.mcp.server_name。 - 透传路由:跨度导出为
passthrough <route>,携带aisix.passthrough.route_name;当路由的identity_header提取到最终用户身份时,aisix.client_identity一并携带。
模型流量仍然使用 chat.completions 这一跨度名称和 gen_ai.operation.name: chat。在此变更之前按这两个值编写的链路查询也会匹配到 Agent 和工具调用,现在只会匹配模型流量——而这本来就是它想表达的含义。
Datadog 日志使用 aisix.requested_model 表示调用方请求的别名,使用 gen_ai.response.model 表示具体响应模型版本,并使用 aisix.model_id 表示解析后的模型资源。
对象存储和阿里云 SLS 会保留底层用量事件字段名称,例如 requested_model、model_id 和 provider_model_version。
导出遥测中的请求类型
每条记录还携带该请求要求网关做的事情——对话补全、图片生成、视频提交、工具调用。取值及其含义参见区分请求类型。
各目的地对它的命名不同:
- 对象存储和阿里云 SLS 保留用量事件字段名
operation。 - Datadog 映射为
aisix.operation。 - OTLP 以
aisix.operation跨度属性携带,并出现在该请求整个跨度层级的每一层上,因此可以在链路的根节点按类型筛选。
OTLP 跨度上同时还有 OpenTelemetry 的 gen_ai.operation.name 属性,两者回答的是不同的问题。后者使用 OpenTelemetry 自己的词汇表,能区分模型推理与 Agent、工具调用,但所有 OpenAI 兼容端点只对应一个取值——因此无法区分对话、图片和视频。端点本身重要时,请按 aisix.operation 过滤。
AISIX Cloud 控制面
控制台在目标环境的 Observability 视图中管理相同的导出器资源。导出器表单会收集目标字段、内容模式和各类型专属选项。
无论导出器通过 API 还是控制台保存,控制面都会把配置投射到关联到该环境的 AISIX 网关。
以下行为适用于投射到 AISIX 网关的导出器:
- AISIX 网关会直接将请求遥测发送到你的目标。控制面不会代理导出的遥测。
- 除非在导出器上启用完整内容采集,否则提示词和响应内容会留在网关上。
- 凭证引用由 AISIX 网关解析。当目标需要运行时凭证时,控制台会展示需要在网关上配置的环境变量。
- 投递健康状态来自网关心跳数据,会显示批次是否正在发送,或网关是否报告了投递错误。
对于 OTLP/HTTP 导出器,控制台提供 Langfuse、Honeycomb 和 Grafana Cloud Tempo 的预设,也接受自定义 OTLP 端点。
Trace UI URL 模板是可选的。当 Request Logs 视图需要将请求记录链接到外部 Trace UI 时使用它。模板必须包含 {request_id},以便控制面用日志记录中的请求 ID 替换它。
下一步
如需在 Snowflake 中查询对象存储遥测,请继续阅读将请求遥测加载到 Snowflake。使用指标和日志将导出记录与网关指标、访问日志和响应头关联。