跳转至

OpenLineage

OpenLineage 是面向数据血缘采集的开放标准。本指南说明如何将 OpenLineage RunEvent、JobEvent 和 DatasetEvent 接入观测云,适用于 Airflow、Spark、dbt 以及直接使用 OpenLineage 客户端的应用。

前置条件

开始前,请准备:

  • 当前站点的数据接入地址,例如 https://openway.guance.com;其他站点或私有部署请使用实际地址。
  • 目标工作空间的 Token。请将 Token 作为密钥管理,不要写入源码或提交到版本库。
  • 支持 OpenLineage HTTP transport 的数据任务或客户端。
  • 从任务运行环境到数据接入地址的 HTTPS 网络连通性。

下文使用以下占位符:

占位符 说明
<OPENLINEAGE_BASE_URL> 不带路径和 query 参数的数据接入地址
<WORKSPACE_TOKEN> 目标工作空间的 Token

接入协议

项目 要求
方法 POST
路径 /v1/write/openlineage
Content-Type application/json,允许携带 charset 参数
Content-Encoding 可省略;压缩时使用 gzip
请求体 单个 OpenLineage RunEvent、JobEvent 或 DatasetEvent JSON 对象
默认请求体上限 64 MiB;gzip 请求按收到的压缩后字节数计算,实际部署可调整;解压后的单条事件不能超过 8 MiB

完整 URL 为:

<OPENLINEAGE_BASE_URL>/v1/write/openlineage

每次请求只发送一个事件,不支持 JSON 数组或 OpenLineage batch 接口。建议保持单条事件远小于上限,避免超大的 Facet 影响发送和重试。

认证

支持以下三种认证方式:

方式 示例 建议
Bearer Authorization: Bearer <WORKSPACE_TOKEN> 推荐,兼容 OpenLineage HTTP transport 的 api_key 认证
Header X-Token: <WORKSPACE_TOKEN> 适合能够设置自定义 Header 的客户端
Query ?token=<WORKSPACE_TOKEN> 仅用于兼容;URL 可能被代理或访问日志记录

如果请求同时提供多种 Token,优先级为 query token、X-Token、Bearer。不要在一个请求中配置多个不同的 Token。

事件要求

事件必须符合 OpenLineage 规范。三种事件都必须包含 eventTime(ISO 8601 时间)、producer(生产者 URI)和 schemaURL(规范版本地址);观测云 根据顶层的 run、job、dataset 识别类型:

事件类型 必填的身份字段 用途
RunEvent run.runId、job.namespace、job.name、eventType 记录一次运行及其输入、输出;eventType 支持 START、RUNNING、COMPLETE、ABORT、FAIL、OTHER
JobEvent job.namespace、job.name;不包含 run 或 dataset 描述 Job 元数据,可包含 inputs、outputs
DatasetEvent dataset.namespace、dataset.name;不包含 run 或 job 描述独立 Dataset 元数据及 Schema/字段血缘 Facet

RunEvent 和 JobEvent 有数据输入或输出时填写 inputs、outputs,每个 Dataset 应有 namespace 和 name。同一次运行的 RunEvent 必须使用相同的 runId、job.namespace 和 job.name;通常先发送 START,结束时再发送 COMPLETE、FAIL 或 ABORT。

事件分类与记录类型

接入后,source 表示原始 OpenLineage 事件的类型,lineage_record_type 表示 观测云 从该事件投影出的记录类型。它们不是同一个维度:同一个 RunEvent 可以生成多条记录,但这些记录的 source 都是 run_event。

source 原始事件 可能生成的 lineage_record_type
run_event RunEvent:一次运行的状态与输入、输出 event、dataset_edge;有相关 Facet 时还可有 schema_version、field_edge
job_event JobEvent:Job 的静态或变更元数据 event、job、dataset_edge;有相关 Facet 时还可有 schema_version、field_edge
dataset_event DatasetEvent:独立 Dataset 的元数据 event、dataset;有相关 Facet 时还可有 schema_version、field_edge

event 保存经过敏感信息脱敏的完整事件 JSON(lineage_message);job、dataset 是实体记录;dataset_edge 表示 Job/Run 的输入或输出 Dataset;schema_version 是 Schema 摘要;field_edge 是字段级血缘。无相关输入、输出或 Facet 时,不会生成对应的派生记录。无效事件的审计记录可能出现 source=unknown_event、lineage_record_type=ingest_error;这不是第四种可发送的事件类型。

source 是 观测云 保留的分类字段。如果原始 JSON 顶层另有字符串 source,投影记录会将其保存在 src_source,不会覆盖 观测云 的 source;原始事件的该字段仍可在 event 记录的 lineage_message 中查看。

查询字段清单

下表是 观测云 提取到一级字段的字段清单,并非 OpenLineage 原始 JSON 的全部字段。字段按事件类型、记录类型及 Facet 是否存在而出现;某个字段未出现,不等于其值为空。需要完整事件时查看 lineage_record_type=event 的 lineage_message(敏感值可能已脱敏)。同一事件的多条投影记录通过 event_id 关联;run_id、job_id、dataset_id 分别用于关联运行、Job 和 Dataset。

通用字段与事件原文

字段 含义
__namespace 固定为 lineage;对应 DQL 的 LN 命名空间
source 事件分类:run_event、job_event、dataset_event;接入错误记录为 unknown_event
src_source 原始 JSON 顶层的字符串 source(如存在)
lineage_record_type 投影记录类型:event、job、dataset、dataset_edge、schema_version、field_edge、ingest_error
event_id 工作空间内按原始事件内容生成的事件标识;同一事件的投影记录共用
date、date_ns 原始 eventTime,分别为毫秒、纳秒 Unix 时间戳;查询时间以此为准
create_time 观测云 收到事件的毫秒时间戳
__docid 存储层的单条记录 ID,不用于实体去重
projection_version、normalization_version 观测云 投影格式和 Dataset 身份归一化版本
lineage_message 脱敏后的完整事件 JSON;只在 event 记录上
producer、schema_url 原始 producer 与 schemaURL;主要在 event,也在 job、dataset 记录上
ingest_delay_ms 接收时间与 eventTime 的差值(毫秒);只在 event 上
facet_names 事件携带的 Facet 名称;只在 event 上
redaction_policy_version、redacted_count 原文脱敏策略版本和脱敏数量;只在 event 上
ingest_warning 可选 Facet 解析失败或投影限额等降级警告代码;只在 event 上

Run 与 Job 字段

身份字段会随同一事件的派生记录传递;Job 名称、状态及 Facet 提取字段主要位于 event,JobEvent 的 Job 元数据还位于 job 记录。

字段 含义
event_type、run_id RunEvent 的状态和原始 run.runId
job_id 观测云 根据工作空间、job.namespace 和 job.name 生成的稳定 Job 标识
job_namespace、job_name 原始 Job 身份;只在 event、job 记录上
parent_run_id、root_run_id parent Run Facet 中的父运行、根运行 ID
parent_job_id、parent_job_namespace、parent_job_name 父 Job 的标识和名称
root_job_id、root_job_namespace、root_job_name 根 Job 的标识和名称
is_terminal、is_success、has_error 是否终态、是否 COMPLETE、是否失败/中止或含错误 Facet
error_type 错误 Facet 中可识别的明确错误类型;不是完整错误消息
error_message、error_language、stacktrace_hash 脱敏后的错误消息、编程语言及堆栈摘要
input_count、output_count 原始输入、输出 Dataset 个数
integration、job_type、processing_type Job 的 jobType Facet
engine_name、engine_version、openlineage_adapter_version Run 的 processing_engine Facet
nominal_start_time、nominal_end_time Run 的计划起止时间(毫秒时间戳)
has_sql、sql_hash 是否有 SQL Facet 及其内容摘要;不暴露完整 SQL
has_config、config_hash 是否有配置 Facet 及其内容摘要
application_id、spark_master、deploy_mode、driver_host、spark_user Spark 应用信息(存在相应 Facet 时)
trace_ids、trace_links 可选的 Trace 关联 ID 列表和关联详情

Dataset、Schema 与血缘边字段

dataset 记录只由 DatasetEvent 生成;dataset_edge 由 RunEvent 或 JobEvent 的输入、输出生成。schema_version 只保留 Schema 摘要,完整 Schema 仍在 lineage_message 的原始 Facet 中。

字段 含义
dataset_id 观测云 根据工作空间与归一化 Dataset 身份生成的稳定标识
dataset_namespace、dataset_name 原始 Dataset 的 namespace、name
dataset_key 归一化后的 Dataset 身份键
dataset_type、data_platform 归一化出的 Dataset 类型、数据平台
account_name、database_name、schema_name、table_name 从 Dataset 身份解析出的层级名称;能解析时才有
data_source_name、data_source_uri Dataset 的 dataSource Facet;描述具体数据源,不等同于 data_platform
lifecycle_state_change Dataset 的生命周期变化状态
io_type dataset_edge 或相关 schema_version 的方向:INPUT / OUTPUT
row_count、size_bytes、file_count 输入/输出统计 Facet 中的行数、字节数、文件数
schema_hash、schema_field_count Schema 字段列表摘要和字段数;可出现在 Dataset、边及 Schema 版本记录
run_dataset_edge_id、job_dataset_edge_id Run/Job 与 Dataset 输入输出关系的稳定标识
observed_at job、dataset、schema_version 的观察时间(毫秒)
input_dataset_id、input_field field_edge 的上游 Dataset 和字段
output_dataset_id、output_field field_edge 的下游 Dataset 和字段
field_edge_id 字段级血缘关系的稳定标识
transformation_type、transformation_subtype、transformation_hash 字段转换类型、子类型及内容摘要
is_masking 字段转换是否为脱敏处理

ingest_error 记录另有 ingest_error_reason_code(拒收原因)、ingest_error_payload_hash(载荷摘要)和 ingest_error_payload_size(载荷字节数);为避免泄漏,不保存原始错误载荷。

快速验证

将以下内容保存为 event.json,并为每次测试生成新的 runId:

{
  "eventType": "START",
  "eventTime": "2026-10-21T08:00:00Z",
  "run": {
    "runId": "4a8f90a7-79c0-4f80-89e7-6b6c5d4fc79a"
  },
  "job": {
    "namespace": "example.scheduler",
    "name": "daily_orders"
  },
  "inputs": [
    {
      "namespace": "postgresql://warehouse.example:5432",
      "name": "sales.orders"
    }
  ],
  "outputs": [
    {
      "namespace": "postgresql://warehouse.example:5432",
      "name": "analytics.daily_orders"
    }
  ],
  "producer": "https://example.com/openlineage/integration",
  "schemaURL": "https://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/RunEvent"
}

使用 Bearer Token 发送:

curl --fail-with-body --silent --show-error \
  -X POST '<OPENLINEAGE_BASE_URL>/v1/write/openlineage' \
  -H 'Authorization: Bearer <WORKSPACE_TOKEN>' \
  -H 'Content-Type: application/json' \
  --data-binary @event.json

使用 gzip 压缩发送:

gzip -c event.json | curl --fail-with-body --silent --show-error \
  -X POST '<OPENLINEAGE_BASE_URL>/v1/write/openlineage' \
  -H 'Authorization: Bearer <WORKSPACE_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Content-Encoding: gzip' \
  --data-binary @-

请求成功后,再使用相同的 runId 和 Job 标识发送 COMPLETE 事件,验证一次完整的运行生命周期。

客户端配置

OpenLineage Python Client

OpenLineage Python Client 的 api_key 认证会生成 Bearer Header。以下配置同时启用 gzip 和对临时错误的重试:

export OPENLINEAGE__TRANSPORT__TYPE=http
export OPENLINEAGE__TRANSPORT__URL='<OPENLINEAGE_BASE_URL>'
export OPENLINEAGE__TRANSPORT__ENDPOINT='/v1/write/openlineage'
export OPENLINEAGE__TRANSPORT__AUTH__TYPE=api_key
export OPENLINEAGE__TRANSPORT__AUTH__APIKEY='<WORKSPACE_TOKEN>'
export OPENLINEAGE__TRANSPORT__COMPRESSION=gzip
export OPENLINEAGE__TRANSPORT__RETRY='{"total":5,"connect":5,"read":5,"backoff_factor":0.3,"status_forcelist":[429,500,502,503,504],"allowed_methods":["POST"]}'

不同客户端版本支持的配置项可能不同,升级前请核对 Python Client 配置说明。

Apache Airflow

安装与当前 Airflow 版本兼容的 OpenLineage Provider,然后配置 HTTP transport:

pip install apache-airflow-providers-openlineage

export AIRFLOW__OPENLINEAGE__NAMESPACE='production-airflow'
export AIRFLOW__OPENLINEAGE__TRANSPORT='{"type":"http","url":"<OPENLINEAGE_BASE_URL>","endpoint":"/v1/write/openlineage","auth":{"type":"api_key","apiKey":"<WORKSPACE_TOKEN>"},"compression":"gzip"}'

Provider 与 Airflow 有版本兼容要求。安装或升级时请查看 Airflow OpenLineage Provider 文档。

Apache Spark

加载与 Spark 版本兼容的 OpenLineage Spark 集成包,并设置以下属性:

spark.extraListeners=io.openlineage.spark.agent.OpenLineageSparkListener
spark.openlineage.transport.type=http
spark.openlineage.transport.url=<OPENLINEAGE_BASE_URL>
spark.openlineage.transport.endpoint=/v1/write/openlineage
spark.openlineage.transport.auth.type=api_key
spark.openlineage.transport.auth.apiKey=<WORKSPACE_TOKEN>
spark.openlineage.transport.compression=gzip
spark.openlineage.namespace=production-spark

集成包的加载方式与版本兼容关系,请参考 OpenLineage Spark 安装文档。

dbt

安装 openlineage-dbt,复用 Python Client 的 transport 配置,并使用 dbt-ol 替代 dbt:

pip install openlineage-dbt

export OPENLINEAGE__TRANSPORT__TYPE=http
export OPENLINEAGE__TRANSPORT__URL='<OPENLINEAGE_BASE_URL>'
export OPENLINEAGE__TRANSPORT__ENDPOINT='/v1/write/openlineage'
export OPENLINEAGE__TRANSPORT__AUTH__TYPE=api_key
export OPENLINEAGE__TRANSPORT__AUTH__APIKEY='<WORKSPACE_TOKEN>'
export OPENLINEAGE__TRANSPORT__COMPRESSION=gzip
export OPENLINEAGE_NAMESPACE='production-dbt'

dbt-ol run

不要只设置 OPENLINEAGE_URL:客户端默认路径通常是 /api/v1/lineage,本接入要求显式配置 /v1/write/openlineage。更多运行模式和适配器支持情况见 OpenLineage dbt 集成文档。

响应与重试

响应 含义 处理建议
2xx 请求已接受 不重试
200 且 error_code 为 dataway.cached 请求已接受并等待后续投递,暂不代表数据已经可查询 不要立即重试;稍后检查数据是否可见
400 或 422 JSON 或 OpenLineage 事件不合法 修正事件后再发送
401 或 403 Token 缺失、无效或无权限 修正认证后再发送
413 请求体超过限制 缩小 Facet 或单条事件大小
415 Content-Type 或 Content-Encoding 不支持 修正请求头或压缩方式
429、500、502、503、504 临时不可用、限流或服务错误 按 Retry-After 重试;未提供时使用带随机抖动的指数退避

发送方必须允许重复投递,并为同一次运行保持稳定的 runId。不要重试确定性的 4xx 错误,否则无效事件可能持续占用发送队列。

验证与排障

完成配置后,建议按以下顺序验证:

  1. 使用 curl 发送最小 START 事件,确认返回 2xx。
  2. 使用相同的 Run 和 Job 标识发送终态事件。
  3. 在观测云中按 Job namespace、Job name 或 runId 查找对应记录。
  4. 检查生产者日志,确认没有持续重试、认证错误或事件序列化错误。

常见问题:

现象 检查项
401 或 403 Token 是否属于目标工作空间;Bearer 是否以 Bearer 加一个空格开头;环境变量是否被正确注入
404 endpoint 是否明确配置为 /v1/write/openlineage,而不是客户端默认的 /api/v1/lineage
413 事件或 Facet 是否过大;gzip 只能降低传输体积,仍建议缩小单条事件
415 Content-Type 是否为 JSON;压缩请求是否同时设置 Content-Encoding: gzip
429 或 503 是否遵循 Retry-After;降低并发并增加带抖动的指数退避
返回成功但暂时查不到数据 是否收到 dataway.cached;Job namespace/name 和 runId 是否与查询条件一致;等待后再次检查
只有 START,没有结束状态 生产者是否在成功、失败和取消路径分别发送 COMPLETE、FAIL 或 ABORT

安全建议

  • 生产环境只使用 HTTPS,并保持证书校验开启。
  • 优先使用 Bearer 或 X-Token,避免在 URL 中携带 Token。
  • 通过 Secret、密钥管理服务或运行环境注入 Token;不要写入镜像、配置模板、命令历史或日志。
  • 定期轮换 Token,并在泄漏后立即撤销旧 Token。
  • Facet 可能包含 SQL、Schema 或业务元数据;发送前评估敏感信息,并按最小必要原则采集。

参考资料

文档评价

文档内容是否对您有帮助?