Add unified emission_policy config for OpenLineage provider#66992
Merged
mobuchowski merged 3 commits intoJun 29, 2026
Conversation
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
force-pushed
the
feat-ol-general-lineage-controls
branch
from
May 22, 2026 14:16
d7dfa89 to
d124bd1
Compare
1 task
kacpermuda
force-pushed
the
feat-ol-general-lineage-controls
branch
from
May 28, 2026 15:16
d124bd1 to
ece44db
Compare
mobuchowski
reviewed
May 29, 2026
kacpermuda
force-pushed
the
feat-ol-general-lineage-controls
branch
from
May 29, 2026 16:18
ece44db to
f1e21ce
Compare
kacpermuda
marked this pull request as ready for review
May 29, 2026 16:18
kacpermuda
marked this pull request as draft
May 29, 2026 16:20
kacpermuda
marked this pull request as ready for review
May 29, 2026 16:20
kacpermuda
force-pushed
the
feat-ol-general-lineage-controls
branch
3 times, most recently
from
June 2, 2026 15:30
462a55a to
e7bd968
Compare
|
Hey @kacpermuda — just updated #63499 with consistent gating across all |
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
force-pushed
the
feat-ol-general-lineage-controls
branch
2 times, most recently
from
June 18, 2026 07:54
cb1cbd2 to
9a6aa05
Compare
mobuchowski
reviewed
Jun 23, 2026
# Conflicts: # generated/provider_dependencies.json.sha256sum
kacpermuda
force-pushed
the
feat-ol-general-lineage-controls
branch
from
June 23, 2026 11:07
9a6aa05 to
33de574
Compare
kacpermuda
force-pushed
the
feat-ol-general-lineage-controls
branch
from
June 23, 2026 12:15
33de574 to
932c25d
Compare
mobuchowski
approved these changes
Jun 29, 2026
1 task
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
75 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces a single
[openlineage] emission_policyconfiguration option that replacesthe 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": ...}:scope(required,{}for global) acceptsdag_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 insidescopeis treated as are.fullmatchpattern.locked: true— admin floor lock; see the admin/dag-author split below.Scope priority (most-specific wins):
dag_id + task_id→dag_id→operator→ 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": trueto make that field non-overridable. Layered on top, Dag authors callextend_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):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 runtimeNot touched — completely unrelated to this change:
transport/config_path— where events go; unchangeddisabled— global kill switch; still takes full precedence over everythingnamespace— logical namespace for events; unchangedextractors/custom_run_facets— extension points; unchangedexecution_timeout/debug_mode/dag_state_change_process_pool_size— operational knobs; unchangedspark_inject_parent_job_info/spark_inject_transport_info— Spark integration; unchangedBackwards compatibility
The four superseded options are not removed. Any active legacy option is always translated into equivalent
emission_policyrules — regardless of whetheremission_policyitself is set. Translated rules are prepended before any user-provided rules, so explicit user rules win within each tier (last-wins).emission_policyis empty: zero warnings, built-in defaults.DeprecationWarningis issued listing every translated option. Migrate toemission_policyexclusively to silence it.The legacy options can be removed in a future version.
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (claude-sonnet-4-5) following the guidelines