Implementation:Apache Airflow Metrics Validators
| Knowledge Sources | |
|---|---|
| Domains | Observability, Metrics, Validation |
| Last Updated | 2026-02-08 21:00 GMT |
Overview
Metric name validation framework enforcing backend-specific naming rules via allow/block list filtering, character set validation, and length constraints for StatsD and OpenTelemetry backends.
Description
The validators module provides a layered validation system for Airflow metric names:
- ListValidator is an abstract base class with a test(name) method that subclasses override to implement allow-list or block-list semantics. Validation lists are parsed from comma-separated configuration strings and matched via regex patterns.
- PatternAllowListValidator permits only metric names that match at least one pattern in the allow list (if no list is set, all metrics are allowed).
- PatternBlockListValidator permits only metric names that do not match any pattern in the block list (if no list is set, all metrics are allowed).
- stat_name_default_handler validates character set (ASCII alphanumerics, underscores, dots, dashes, forward slashes) and length (default max 250 characters).
- stat_name_otel_handler extends default validation with OpenTelemetry-specific constraints (max 255 characters) and supports a back-compatibility exemption list for legacy metric names that exceed the length limit.
- validate_stat is a decorator that wraps metric emission methods to invoke the configured handler and suppress invalid names via InvalidStatsNameException.
Usage
Validators are configured through the [metrics] section of airflow.cfg using metrics_allow_list and metrics_block_list options. The get_validator() factory selects the appropriate validator type. If both lists are specified, the allow list takes precedence and the block list is ignored with a warning.
Code Reference
Source Location
- Repository: Apache Airflow
- File: shared/observability/src/airflow_shared/observability/metrics/validators.py (279 lines)
Signature
class ListValidator(metaclass=abc.ABCMeta):
"""Abstract base for allow/block list metric validators."""
def __init__(self, validate_list: str | None = None) -> None: ...
@abc.abstractmethod
def test(self, name: str) -> bool: ...
class PatternAllowListValidator(ListValidator):
"""Match the provided strings anywhere in the metric name."""
def test(self, name: str) -> bool: ...
class PatternBlockListValidator(ListValidator):
"""Only allow names that do not match the blocked strings."""
def test(self, name: str) -> bool: ...
def stat_name_default_handler(
stat_name: str,
max_length: int = 250,
allowed_chars: Iterable[str] = ALLOWED_CHARACTERS,
) -> str: ...
def stat_name_otel_handler(
stat_prefix: str,
stat_name: str,
max_length: int = 255,
) -> str: ...
def get_current_handler_stat_name_func(
stat_name_handler: Callable[[str], str] | None = None,
statsd_influxdb_enabled: bool = False,
) -> Callable[[str], str]: ...
def get_validator(
metrics_allow_list: str | None = None,
metrics_block_list: str | None = None,
) -> ListValidator: ...
def validate_stat(fn: Callable) -> Callable: ...
Import
from airflow_shared.observability.metrics.validators import (
PatternAllowListValidator,
PatternBlockListValidator,
stat_name_default_handler,
stat_name_otel_handler,
get_validator,
get_current_handler_stat_name_func,
validate_stat,
)
I/O Contract
stat_name_default_handler
| Name | Type | Required | Description |
|---|---|---|---|
| stat_name | str | Yes | The metric name to validate |
| max_length | int | No | Maximum allowed length (default: 250) |
| allowed_chars | Iterable[str] | No | Set of valid characters (default: ASCII alphanumerics + _.-/) |
Returns the validated stat name or raises InvalidStatsNameException.
stat_name_otel_handler
| Name | Type | Required | Description |
|---|---|---|---|
| stat_prefix | str | Yes | The metric prefix (e.g., "airflow") |
| stat_name | str | Yes | The metric name |
| max_length | int | No | Maximum combined length (default: 255 per OTel spec) |
Returns the combined prefix.stat_name or raises InvalidStatsNameException.
get_validator
| Name | Type | Required | Description |
|---|---|---|---|
| metrics_allow_list | str | No | Comma-separated allow patterns |
| metrics_block_list | str | No | Comma-separated block patterns |
Returns a configured ListValidator instance.
Validation Rules
Character Set
ALLOWED_CHARACTERS = frozenset(string.ascii_letters + string.digits + "_.-/")
Validator Selection Priority
| Condition | Validator Type | Behavior |
|---|---|---|
| metrics_allow_list is set | PatternAllowListValidator | Only matching metrics are emitted |
| metrics_block_list is set (no allow list) | PatternBlockListValidator | Matching metrics are suppressed |
| Neither is set | PatternAllowListValidator(None) | All metrics are allowed |
| Both are set | PatternAllowListValidator | Allow list wins; block list ignored with warning |
Back-Compatibility Exemptions (OTel)
The module defines BACK_COMPAT_METRIC_NAME_PATTERNS, a set of 22 regex patterns for legacy metric names that exceed the OpenTelemetry 255-character limit. These names are permitted with a deprecation warning rather than being rejected. No new names should be added to this list.
Usage Examples
Configuring Validators
from airflow_shared.observability.metrics.validators import get_validator
# Allow only scheduler and task metrics
validator = get_validator(metrics_allow_list="scheduler,task_instance")
assert validator.test("scheduler.heartbeat") is True
assert validator.test("pool.open_slots") is False
# Block pool metrics
validator = get_validator(metrics_block_list="pool")
assert validator.test("scheduler.heartbeat") is True
assert validator.test("pool.open_slots") is False
Validating Stat Names
from airflow_shared.observability.metrics.validators import stat_name_default_handler
# Valid name passes through
name = stat_name_default_handler("dag.my_dag.task.duration")
# Invalid characters raise InvalidStatsNameException
stat_name_default_handler("dag:my dag!") # Raises InvalidStatsNameException