Apache Airflow metrics with StatsD and OpenTelemetry

How to choose between StatsD and OpenTelemetry for Airflow metrics, keep multiple schedulers distinguishable, control metric volume and alert on the signals that show pipelines are failing or waiting.

On this page

Apache Airflow metrics with StatsD and OpenTelemetry: which emitter fits your platform

Airflow emits metrics through the [metrics] section of its configuration, and you can send them to either StatsD or OpenTelemetry. Until you choose one, a self-hosted Airflow can look healthy from the UI while scheduler lag, parse failures and pool saturation go unseen. The choice matters most once you run more than one scheduler, because the way each emitter identifies its source determines whether the numbers you alert on are trustworthy. This work is worth planning before the first production deployment, and again before you add a second scheduler or change how DAGs are parsed.

The difference that drives the decision is attribution. StatsD cannot tell which process produced a metric, so several schedulers can overwrite each other's values under the same name. OpenTelemetry sets service.instance.id for each process, which keeps schedulers distinct. Confirm this behavior against your Airflow version in the Airflow metrics configuration reference, and check which emitter your existing monitoring stack already accepts. Also confirm how your platform team will receive OpenTelemetry data, whether directly or through a Collector.

This section covers the emitter choice, the settings that switch it on, and the operational scope around it. It does not cover the backend that stores, queries and charts the metrics, such as Prometheus, Grafana or a commercial service. Those choices, their retention and their alert routing are separate decisions, and they should be made with the same team that owns on-call. Ask your platform team which backend they will use, how long metrics must be kept, and who receives each alert before you fix the emitter.

StatsD or OpenTelemetry: how the two emitters differ for Airflow

This is the factor that most often decides the question. Airflow can run more than one scheduler at once for performance and resiliency, but StatsD has no way to tell which process produced a given metric. When several schedulers send the same metric names, their values overwrite or blend into each other, so a heartbeat or parse-time reading may describe a scheduler you are not looking at. OpenTelemetry avoids this by setting a service.instance.id for each process, so each scheduler's series stays separate and can be filtered individually. If you run a single scheduler, StatsD attribution is less of a concern. If you run several, plan on OpenTelemetry or confirm that your StatsD pipeline can distinguish senders in some other way.

  • Single scheduler: StatsD attribution is rarely a problem, so this factor alone does not force a choice.
  • Multiple schedulers: StatsD series from different schedulers can overwrite one another under the same metric name.
  • Per-process identity: OpenTelemetry sets service.instance.id per process, which keeps each scheduler's readings distinct.
  • Heartbeat checks: A per-instance scheduler_heartbeat is only reliable per scheduler if each one is identifiable.
  • Test before rollout: Start two schedulers in a non-production environment and confirm that each one's series appears separately.

Before you go live, check that your chosen emitter shows one series per scheduler for scheduler_heartbeat and dag_processing.total_parse_time.

Metrics configuration options and when each fits

This table compares the [metrics] settings and custom metric calls that shape how Airflow emits telemetry, and the situation each one fits. Read each row as a decision point: pick the backend first, then add naming and filtering controls. Confirm exact key names against the Airflow metrics configuration reference before you change a production file.

Setting or callWhat it controlsWhen it fits
statsd_on or otel_on (backend choice)Turns on StatsD or OpenTelemetry emission from the [metrics] sectionChoose StatsD when you already run a StatsD receiver; choose OpenTelemetry for per-process attribution with several schedulers
statsd_host and statsd_portAddress of the StatsD receiver that Airflow sends UDP metrics toSingle-scheduler setups or existing StatsD pipelines; confirm the receiver accepts the metric names Airflow sends
statsd_prefixPrefix added to every StatsD metric nameMultiple Airflow environments sharing one receiver, so staging and production series stay separate
otel_host, otel_port and related OTLP keysEndpoint, port and transport for OpenTelemetry export, typically a CollectorMulti-scheduler deployments where each process should be identifiable through service.instance.id
metrics_allow_listRegular expression list of metric names to keepCutting volume to a known set of alert metrics such as scheduler heartbeat and pool slots
metrics_block_listRegular expression list of metric names to dropRemoving noisy metrics after the allow list is too broad to narrow further
stats.incr (airflow.sdk.observability)Increments a counter from task codeCounting business events such as rows processed or files skipped inside a task
stats.gaugeRecords a point-in-time value from task codeReporting a current size, backlog or queue depth observed during a run
stats.timingRecords a duration from task codeTracking how long a call to an external API or database takes per run

Setting up Airflow metrics in order

This sequence takes a self-hosted Airflow from no metrics to a verified pipeline that shows which scheduler emitted each signal, filters the noise, and carries task-level metrics into your alerting. Each step ends with a check so you know the layer below works before you build on it.

  1. Choose StatsD or OpenTelemetry as the emitter

    Your platform team decides which emitter Airflow uses, based on what already receives telemetry in your environment. StatsD is simpler when you already run a StatsD receiver, but it cannot attribute metrics to the process that produced them, so several schedulers will overwrite each other's values. OpenTelemetry sets a service.instance.id for each process, which keeps schedulers distinct. Confirm the choice against the Airflow metrics configuration before you write any settings. The output is a written decision that names the receiver and the backend that will store the data.

  2. Set the metrics section in airflow.cfg

    The engineer responsible for the Airflow deployment sets the [metrics] section for the chosen emitter, using the same configuration on every component that emits metrics. Keep these settings in version-controlled configuration, not in a hand-edited file on a single host. Set the host and port of the StatsD receiver or the OpenTelemetry endpoint, and use one prefix convention across all environments. Check the exact keys against the metrics documentation for your Airflow version, since names differ between StatsD and OpenTelemetry settings. Done means a configuration review has passed and the values are deployed to the scheduler, DAG processor, API server and workers.

  3. Confirm each component's process identity

    Before you rely on dashboards, confirm that each scheduler, DAG processor, API server and worker reports under its own identity. With OpenTelemetry, check that service.instance.id differs per process. With StatsD, plan a per-instance naming scheme or move to OpenTelemetry if you run more than one scheduler, since StatsD cannot separate their series. Start two schedulers in a test environment and compare their emitted series. Done means each component appears as a separate source in your backend, and you can name the one that produced any heartbeat.

  4. Apply allow and block lists

    Set metrics_allow_list and metrics_block_list as regular expressions to limit what leaves Airflow. Start from a short allow list covering scheduler, DAG processing, task failure and pool metrics, then widen it only when a dashboard or alert needs more. Block high-cardinality series that carry identifiers you do not need to query, and review the list whenever you add DAGs with many tasks. Test each expression against the metric names in a non-production environment, since a mistake here silently drops data. Done means the emitted metric set matches the list you reviewed, and the alert metrics are still present.

  5. Deploy the Collector or StatsD receiver

    The platform team deploys the receiver that sits between Airflow and your backend. For OpenTelemetry, that is usually an OpenTelemetry Collector, which can run as an agent beside Airflow or as a gateway that receives from several sources. Configure its receivers, processors and exporters in version-controlled files, and restrict the receiver endpoints to the networks where Airflow runs. Follow the collector configuration best practices for authentication and transport settings, and use authenticator extensions if your security policy requires them. Done means the receiver is running, reports healthy, and accepts a test metric from an Airflow component.

  6. Verify scheduler heartbeat and pool slot metrics

    Confirm that the core metrics reach your backend. Look for scheduler_heartbeat from every scheduler, dag_processing.import_errors and dag_processing.total_parse_time from the DAG processor, and pool.open_slots, pool.running_slots and pool.queued_slots for a pool with a known workload. Trigger a test DAG to create task activity, and confirm that ti_failures appears with dag_id and task_id tags after a deliberate failure in a sandbox. Done means every example metric is visible with the expected source label, and a missing heartbeat from one scheduler would be detectable on a dashboard.

  7. Add task-level custom metrics

    Once the platform metrics are verified, DAG authors can emit their own signals from tasks using airflow.sdk.observability with stats.incr, stats.gauge and stats.timing. Agree on a naming convention and a small set of tags with the platform team before anyone adds metrics, so that series from different teams stay comparable. Keep tag values bounded, since unbounded values create many series. Test a custom metric in staging and confirm it passes the allow list you set in the earlier step. Done means one task emits a custom metric that appears in your backend under the agreed name, and the team has documented what each metric means for alerting.

Telling schedulers apart when several run at once

Running more than one scheduler is a supported way to improve throughput and resilience in Airflow, because the schedulers coordinate through database row-level locks rather than through a central leader. That design means each scheduler does real scheduling work, so its metrics describe a different slice of the workload. The metrics problem starts with StatsD. StatsD cannot attribute a metric to the process that produced it, so when several schedulers send the same metric names, such as scheduler_heartbeat, the values overwrite each other and the dashboard shows one blended series that looks healthy even when one scheduler has stopped.

OpenTelemetry avoids this by attaching a service.instance.id to each process, so every scheduler produces its own series. Choose OpenTelemetry if you run more than one scheduler and need to see each one separately. Confirm the exact resource attributes your Airflow version emits by checking the metrics configuration documentation and a test run, since attribute names and where they appear in your backend depend on your Collector and storage setup. Once you have a test environment with two schedulers, stop one on purpose and confirm that its series goes stale while the other continues to report.

Per-process identity has a cost. Every scheduler instance adds a set of series for each metric and each label combination, including dag_id and task_id tags on metrics such as ti_failures. Many instances multiplied by many DAGs and tasks can grow your storage and query load quickly, so agree on a label policy before you enable it. Use allow and block lists to drop metrics you do not alert on, and ask your backend team what series count they can support. Also confirm that your dashboards filter by instance and aggregate deliberately, so a per-instance view does not become the default view for every panel.

Which metrics matter for alerting on Airflow

Most Airflow alerts come from a small set of signals: whether schedulers are alive, whether DAGs parse cleanly, whether tasks fail, and whether pools are saturated. Each signal points to a different part of the system, so design each alert around the question it answers rather than a single generic threshold.

Scheduler heartbeat

The scheduler_heartbeat metric shows that a scheduler process is still looping. Alert on the absence of the heartbeat for each scheduler, not on the aggregate, because one dead scheduler can hide behind a healthy peer. Set the window from the scheduler's observed loop cadence in your own environment, and confirm how your StatsD or OpenTelemetry setup labels each process before relying on per-instance alerts.

DAG import errors and parse time

dag_processing.import_errors counts DAG files that fail to load, and dag_processing.total_parse_time shows how long a full parsing pass takes. Alert on a sustained nonzero import error count, since a broken file can stop a pipeline from being scheduled at all. Trend parse time against a baseline you set for your environment, and treat a sudden jump after a deploy as a change signal.

Task failures by DAG and task

ti_failures, tagged by dag_id and task_id, shows where failures concentrate. Alert on a rate change for a specific DAG or task rather than on the total, so a noisy but expected failure does not drown out a new one. Keep the tag cardinality in mind when you allow or block metrics, because every distinct DAG and task pair becomes its own time series.

Pool slot saturation

pool.open_slots, pool.running_slots and pool.queued_slots describe how close each pool is to its limit. Sustained zero open slots combined with a growing queue usually means a pool is protecting a database or API correctly but is undersized for its demand. Alert on queue growth that persists over time, and check whether the queued tasks are waiting for slots or for executor capacity.

Missing metrics as a failure signal

A metric that stops arriving is often more serious than a metric with a bad value. Alert on the absence of expected series from the StatsD exporter or the OpenTelemetry Collector, including the heartbeat, which can go silent when the metrics pipeline breaks rather than Airflow. Confirm how your collector reports stale series, and test the alert by stopping one scheduler in a non-production environment.

Questions teams ask before building Airflow metrics

Should we choose StatsD or OpenTelemetry for Airflow metrics?

Choose OpenTelemetry when you run more than one scheduler, because StatsD cannot attribute metrics to the process that produced them, so schedulers overwrite each other. OpenTelemetry sets a service.instance.id for each process, which keeps series separate. StatsD remains a workable choice for a single scheduler with an existing StatsD pipeline. Set the choice in the [metrics] section, and confirm which exporter and backend your monitoring team already runs before committing. The Airflow metrics configuration lists the settings for each option.

How much effort does Airflow metrics work take, and what drives it?

Effort depends on how many schedulers, workers and DAGs you run, whether a metrics backend already exists, and how many alerts you need on day one. The core configuration is short. Most of the work sits in deciding which metrics feed which alerts, building dashboards, and testing that series stay separated across processes. Ask any partner for a written scope that lists the components, the environments and the alerts covered, since that scope sets the quote. No duration is given here because it depends on those factors in your environment.

What must our team provide before metrics work starts?

You need to provide four things:

  • A metrics backend such as a Prometheus-compatible store, or an OpenTelemetry Collector path to your chosen backend.
  • Network access from Airflow components to the StatsD host or the Collector endpoint, including firewall rules in each environment.
  • Named owners for alerts, with an on-call rota that receives them.
  • A list of schedulers, workers and DAG teams whose metrics you need.

OpenTelemetry Collector releases are licensed under Apache-2.0, so confirm the distribution your security team approves. Confirm each item with your own platform owners before work begins.

Can our in-house team set up Airflow metrics without a partner?

Yes, if your team already operates Airflow, a metrics backend and an alerting workflow. The configuration itself is documented in the Airflow metrics reference, and the OpenTelemetry Collector has published configuration docs. The skills gap is usually in tuning: deciding which series to keep, writing alert thresholds that match your scheduler behavior, and keeping the setup working across Airflow upgrades. A partner is useful when those skills are missing or when the work must fit into a scoped, written deliverable.

How do we govern custom metrics emitted from tasks?

Set a naming convention and an owner for each custom metric before tasks emit them. Tasks can emit custom metrics through the airflow.sdk.observability module with stats.incr, stats.gauge and stats.timing. Review those calls in code review like any other change, and keep tag values bounded so that no unique identifier becomes a label. Require each team to document the business meaning of its metrics so that dashboards and alerts do not depend on undocumented names.

How do we control metric volume and cardinality?

Use metrics_allow_list and metrics_block_list regular expressions to limit what Airflow emits. Start with the metrics that drive alerts, such as scheduler heartbeat, import errors and pool slots, then add others only when a team needs them. Watch tags like dag_id and task_id, because each unique combination creates a separate series. Review series counts after each new DAG wave, and ask your metrics backend team what retention and ingestion limits apply.

What changes after an Airflow upgrade, and what should we check?

Metric names, labels and available options can change between releases, so treat each upgrade as a change to your alerting. Airflow 3 is the current major line, and Airflow 2 reached end of life on April 22, 2026, so plan any upgrade on the vendor's published support table. After upgrading, compare emitted metric names against your alert rules, check that schedulers still report separate instances, and confirm dashboards still load data. Keep a test environment that runs the same metrics configuration before production.

Why the OpenTelemetry Collector is a neutral layer

OpenTelemetry is a framework, not a monitoring backend. It defines how telemetry is generated, exported and collected, but it does not store or visualize anything. The storage and dashboards are separate tools that you choose. For Airflow, this means the decision about where scheduler and task metrics end up can be made later, and changed later, without rewriting how Airflow emits them. The OpenTelemetry Collector is the component that sits between Airflow and those tools. It receives telemetry, processes it (for example, dropping or renaming series), and exports it to one or more destinations. The Collector is licensed under Apache-2.0, the same license as Airflow, so the layer itself carries no license fee for your team to plan around.

Run the Collector as an agent next to the schedulers, workers and API server, or as a gateway that accepts data from many sources, and decide which pattern fits your network before you pin a version. Confirm where your Collector distribution comes from and whether the components you need are contrib or core, because component stability varies and is documented in each component's README. The project publishes releases frequently (v0.161.0 on September 16, 2026, v0.162.0 on September 29, and v0.163.0 on October 16, 2026), so check the OpenTelemetry Collector releases page for the current release, its signed artifacts, checksums and SBOM files, and pin a version your change process can test and roll back. Authenticator extensions can protect the receiving endpoint and add credentials on export, which matters when metrics leave your network.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.