sparkforensics-operator
An Airflow operator that runs sparkforensics analysis on a Spark job's event log right after it finishes, then acts on the result: persist the report, push it to XCom, notify (via any messaging/paging system you implement), and optionally fail the DAG if a budget was breached.
Airflow tells you a Spark task succeeded. It doesn't tell you that stage 14 spilled 40GB from a skewed join, or that runtime crept 20% past last week's run. This package closes that gap without a separate monitoring job: it runs as part of the DAG, right where the Spark task just ran.
Why this exists
- Two ways to wire it in: a standalone
SparkForensicsOperatorthat fails the DAG on a threshold breach, or aspark_forensics_callbackfactory to attach ason_success_callbackon the Spark task itself, log-only. - Three ways to get the event log: fetch it from the Spark History Server, read it from a filesystem/mounted-HDFS path template, or pull it straight out of XCom if the upstream task already has it.
- Budget thresholds mirror
sparkforensics-analyze's own CLI flags (max runtime, spill, skew, failed-task rate, min efficiency); only the ones you configure are enforced, and a breach raisesThresholdBreachedwithout consuming the task's retries, since re-running would just reach the same verdict. - Reports persist to a local path,
file://, ors3://, and a clickable "SparkForensics report" link shows up on the task in the Airflow UI. - An optional
Notifieryou implement (Slack, MS Teams, email, PagerDuty, ZenDuty, whatever you use) gets a best-effort pass/fail summary; a delivery failure never fails the task itself. - Tested against both Airflow 2.6+ and Airflow 3.0+ (CI matrix, Python 3.9-3.12). 97 tests, 96% coverage, no live Spark/Airflow/Node needed to run them: everything is mocked.
Quick start
pip install sparkforensics-operator
Standalone operator, chained after the Spark task, fails the DAG on breach:
from sparkforensics_operator import FilesystemLogSourceHook, SparkForensicsOperator, SubprocessAnalyzeHook
run_spark_job = SparkSubmitOperator(task_id="run_spark_job", ...)
check_spark_job = SparkForensicsOperator(
task_id="check_spark_job",
log_source=FilesystemLogSourceHook(path_template="/mnt/spark-logs/{run_id}/eventlog"),
backend=SubprocessAnalyzeHook(),
report_dest="s3://reports/{{ run_id }}/report.json",
max_runtime_ms=3_600_000,
max_skew_ratio=3,
on_threshold_breach="fail",
)
run_spark_job >> check_spark_job
Or attach it as a callback instead. Airflow logs and swallows any exception
raised inside a callback, so a breach here never fails or retries the
upstream task, whatever on_threshold_breach is set to:
from sparkforensics_operator import SubprocessAnalyzeHook, XComLogSourceHook, spark_forensics_callback
run_spark_job = SparkSubmitOperator(
task_id="run_spark_job",
on_success_callback=spark_forensics_callback(
log_source=XComLogSourceHook(task_id="run_spark_job"),
backend=SubprocessAnalyzeHook(),
report_dest="s3://reports/run_spark_job/app.json",
max_runtime_ms=3_600_000,
),
...,
)
The worker needs Node.js (>=22.18.0 <23.0.0 || >=23.6.0) and the
sparkforensics npm package installed, so sparkforensics-analyze is
resolvable on PATH. Add the s3 extra if report_dest is s3://....
Full details in docs/runbook.md.
Development
pip install -e ".[test,s3]"
pytest
Test against a specific Airflow major version:
tox -e py311-airflow2
tox -e py311-airflow3
Learn more
- Architecture, components and design decisions
- API reference, the full operator/hook/threshold surface
- Runbook, worker prerequisites and troubleshooting
- Glossary, domain terms
License
Release files for sparkforensics-operator 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sparkforensics_operator-0.1.0.tar.gz | 45.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sparkforensics_operator-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.7 kB
Release files / sparkforensics_operator-0.1.0.tar.gz
| Download URL | sparkforensics_operator-0.1.0.tar.gz |
|---|---|
| Size | 45.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dceb50486e2f2ba4f5fc373ac029f46b82f3486f5fa2948b64770aabee6df4ad
|
|
BLAKE2b-256 checksum How to use checksums |
879c29ae137b845d2f6b5921085fab74544805239f5d2d314b1607333390f725
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency logRelease files / sparkforensics_operator-0.1.0-py3-none-any.whl
| Download URL | sparkforensics_operator-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d70dde4887156ec2257ed959371c1ae61e60d4f4c7784f01f2385134520f0c6f
|
|
BLAKE2b-256 checksum How to use checksums |
158c6e31031de7ef5db4fa70d47402340ed54262f47d3b1216b8d6ba93c503c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency log