Skip to content

Add unified emission_policy config for OpenLineage provider#66992

Merged
mobuchowski merged 3 commits into
apache:mainfrom
kacpermuda:feat-ol-general-lineage-controls
Jun 29, 2026
Merged

Add unified emission_policy config for OpenLineage provider#66992
mobuchowski merged 3 commits into
apache:mainfrom
kacpermuda:feat-ol-general-lineage-controls

Conversation

@kacpermuda

@kacpermuda kacpermuda commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Introduces a single [openlineage] emission_policy configuration option that replaces
the patchwork of per-feature toggles with one coherent rule language, plus a Dag-author
authoring API.

What changed

New config: emission_policy — a JSON array of rule objects. Each rule has shape
{"scope": {...}, "controls": {...}, "match_mode": ..., "locked": ...}:

[openlineage]
emission_policy = [
  {"scope": {"operator": "airflow.providers.http.operators.http.HttpOperator"},
   "controls": {"emit": false}},
  {"scope": {"dag_id": "expensive_dag"}, "controls": {"extract_operator_metadata": false}},
  {"scope": {"dag_id": "expensive_dag", "task_id": "send_report"},
   "controls": {"extract_operator_metadata": true}},
  {"scope": {"dag_id": "reporting_dag"}, "controls": {"emit_dag_events": false}},
  {"scope": {"dag_id": "^staging_.*"}, "match_mode": "regex", "controls": {"emit": false}},
  {"scope": {"dag_id": "audit_dag"}, "controls": {"include_full_task_info": true}},
  {"scope": {}, "controls": {"include_source_code": false}, "locked": true}
]
  • scope (required, {} for global) accepts dag_id, task_id, operator. Scope must be exactly one of: global, operator-only, dag-only, or dag+task.
  • controls (required, non-empty): emit, emit_task_events, emit_dag_events, extract_operator_metadata, include_source_code, hook_lineage, include_full_task_info.
  • match_mode: "regex" — every value inside scope is treated as a re.fullmatch pattern.
  • locked: true — admin floor lock; see the admin/dag-author split below.

Scope priority (most-specific wins): dag_id + task_iddag_idoperator → global. Within a tier, last rule wins.

Admin vs Dag-author split - no Airflow restart required. The conf option is the admin lever: it lives in airflow.cfg, applies deployment-wide, and an admin can mark any rule "locked": true to make that field non-overridable. Layered on top, Dag authors call extend_global_openlineage_emission_policy(dag_or_task, ...) directly in DAG code to adjust the policy at parse time without restarting Airflow. Authoring overrides win against unlocked conf rules but cannot touch fields the admin has locked, so admins retain hard guarantees while DAG authors keep day-to-day flexibility.

Strict validation — unknown keys at any nesting level cause the rule to be skipped with a WARNING (catches typos like {"scope": {"dag_id": ...}}).

Audit logging — every non-default resolved flag is logged at INFO with the exact rule that caused it, giving a clear audit trail.

Contradiction detection — two rules in the same priority tier setting the same flag to opposite values trigger a WARNING (last value still wins).

Scope of change — which configs are affected

Superseded by emission_policy (these four control what is emitted and how much):

Legacy option Translated to
disabled_for_operators = some.Operator {"scope": {"operator": "some.Operator"}, "controls": {"emit": false}} (one per entry)
disable_source_code = True {"scope": {}, "controls": {"include_source_code": false}}
include_full_task_info = True {"scope": {}, "controls": {"include_full_task_info": true}}
selective_enable = True {"scope": {}, "controls": {"emit": false}} global baseline + per-task opt-in rules injected at runtime

Not touched — completely unrelated to this change:

  • transport / config_pathwhere events go; unchanged
  • disabled — global kill switch; still takes full precedence over everything
  • namespace — logical namespace for events; unchanged
  • extractors / custom_run_facets — extension points; unchanged
  • execution_timeout / debug_mode / dag_state_change_process_pool_size — operational knobs; unchanged
  • spark_inject_parent_job_info / spark_inject_transport_info — Spark integration; unchanged

Backwards compatibility

The four superseded options are not removed. Any active legacy option is always translated into equivalent emission_policy rules — regardless of whether emission_policy itself is set. Translated rules are prepended before any user-provided rules, so explicit user rules win within each tier (last-wins).

  • When no legacy option is set and emission_policy is empty: zero warnings, built-in defaults.
  • When any legacy option is set: a DeprecationWarning is issued listing every translated option. Migrate to emission_policy exclusively to silence it.

The legacy options can be removed in a future version.


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (claude-sonnet-4-5)

Generated-by: Claude Code (claude-sonnet-4-5) following the guidelines

@mobuchowski

Copy link
Copy Markdown
Contributor

If we want to control dag-level behavior, it should be something - decorator, config - that is configurable per dag in dag code. Otherwise, a restart is required to change it - which is too cumbersome for many customers, especially with large setups.

@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch from d7dfa89 to d124bd1 Compare May 22, 2026 14:16
@kacpermuda kacpermuda changed the title Add unified lineage_controls config for OpenLineage provider Add unified emission_policy config for OpenLineage provider May 28, 2026
@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch from d124bd1 to ece44db Compare May 28, 2026 15:16
Comment thread providers/openlineage/src/airflow/providers/openlineage/extractors/manager.py Outdated
Comment thread providers/openlineage/src/airflow/providers/openlineage/extractors/manager.py Outdated
Comment thread providers/openlineage/src/airflow/providers/openlineage/conf.py
Comment thread providers/openlineage/src/airflow/providers/openlineage/utils/emission_policy.py Outdated
Comment thread providers/openlineage/src/airflow/providers/openlineage/utils/emission_policy.py Outdated
Comment thread providers/openlineage/src/airflow/providers/openlineage/utils/emission_policy.py Outdated
@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch from ece44db to f1e21ce Compare May 29, 2026 16:18
@kacpermuda
kacpermuda marked this pull request as ready for review May 29, 2026 16:18
@kacpermuda
kacpermuda marked this pull request as draft May 29, 2026 16:20
@kacpermuda
kacpermuda marked this pull request as ready for review May 29, 2026 16:20
@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch 3 times, most recently from 462a55a to e7bd968 Compare June 2, 2026 15:30
@potiuk potiuk added the ready for maintainer review Set after triaging when all criteria pass. label Jun 3, 2026
@shnhdan

shnhdan commented Jun 8, 2026

Copy link
Copy Markdown

Hey @kacpermuda — just updated #63499 with consistent gating across all
get_hook_lineage_collector() calls in s3.py. Wanted to flag that the
two PRs are complementary — #66992 controls the OL listener read side,
#63499 gates the calls at the source. Happy to coordinate if needed.

shnhdan added a commit to shnhdan/airflow that referenced this pull request Jun 14, 2026
Following the default_deferrable pattern, add a new [lineage] section
to airflow.cfg with default_hook_lineage boolean (default: True).

S3Hook.__init__ now reads this as the default for enable_hook_level_lineage
instead of hardcoding True. Allows global disabling via config while
permitting per-instance override.

Usage:
  [lineage]
  default_hook_lineage = False   # airflow.cfg

  S3Hook(enable_hook_level_lineage=False)  # per-instance

As suggested by @kacpermuda in review. Pattern can be extended to
other hooks in future PRs.

Related: apache#66992
@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch 2 times, most recently from cb1cbd2 to 9a6aa05 Compare June 18, 2026 07:54
# Conflicts:
#	generated/provider_dependencies.json.sha256sum
@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch from 9a6aa05 to 33de574 Compare June 23, 2026 11:07
@kacpermuda
kacpermuda force-pushed the feat-ol-general-lineage-controls branch from 33de574 to 932c25d Compare June 23, 2026 12:15
@mobuchowski
mobuchowski merged commit 7468284 into apache:main Jun 29, 2026
82 checks passed
@kacpermuda
kacpermuda deleted the feat-ol-general-lineage-controls branch June 29, 2026 10:00
karenbraganz pushed a commit to karenbraganz/airflow that referenced this pull request Jun 30, 2026
…6992)

* feat: Add detailed and extensible lineage controls

* Small cleanup

# Conflicts:
#	generated/provider_dependencies.json.sha256sum

* Few more improvements and tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants