ykuc opened a new issue, #69451:
URL: https://github.com/apache/airflow/issues/69451
### Under which category would you file this issue?
Airflow Core
### Apache Airflow version
3.2.2
### What happened and how to reproduce it?
airflow_shared.observability.metrics.statsd_logger.get_statsd_logger() calls
the StatsD client as:
statsd = stats_class(host, port, prefix, ipv6)
What happened
We run Airflow in an IPv6-only Kubernetes environment and send Airflow
metrics to a StatsD endpoint.
Even with IPv6 StatsD support enabled:
AIRFLOW__METRICS__STATSD_ON=True
AIRFLOW__METRICS__STATSD_HOST=<ipv6-only-statsd-service-hostname>
AIRFLOW__METRICS__STATSD_PORT=8125
AIRFLOW__METRICS__STATSD_PREFIX=airflow
AIRFLOW__METRICS__STATSD_IPV6=True
Airflow components, for example workers, fail to configure the StatsD
metrics client and fall back to NoStatsLogger.
Example log:
{
"logger": "airflow._shared.observability.metrics.stats",
"timestamp": "2026-07-03T18:45:26.741537Z",
"level": "ERROR",
"loc": "stats.py:108",
"message": "Could not configure StatsClient: [Errno -5] No address
associated with hostname, using NoStatsLogger instead."
}
As a result, metrics from the affected Airflow component are not emitted.
What I think should happen
When AIRFLOW__METRICS__STATSD_IPV6=True / [metrics] statsd_ipv6 = True is
set, Airflow should initialize the default statsd.StatsClient with ipv6=True,
so the StatsD host is resolved using IPv6.
Metrics should be sent successfully to an IPv6-only StatsD endpoint.
Probable root cause
The probable issue is in:
airflow_shared/observability/metrics/statsd_logger.py
Current code calls the StatsD client positionally:
statsd = stats_class(host, port, prefix, ipv6)
However, the default statsd.StatsClient constructor has this signature:
StatsClient(
host="localhost",
port=8125,
prefix=None,
maxudpsize=512,
ipv6=False,
)
So Airflow's ipv6 value is passed as the fourth positional argument, which
means it lands in maxudpsize, not in ipv6.
Effectively:
stats_class(host, port, prefix, True)
becomes:
StatsClient(
host=host,
port=port,
prefix=prefix,
maxudpsize=True,
ipv6=False,
)
Therefore statsd_ipv6=True never actually enables IPv6 sockets for the
default StatsD client.
How to reproduce
Use an IPv6-only hostname for statsd_host, for example a Kubernetes Service
that only resolves to an AAAA record.
Set:
AIRFLOW__METRICS__STATSD_ON=True
AIRFLOW__METRICS__STATSD_HOST=<ipv6-only-statsd-service-hostname>
AIRFLOW__METRICS__STATSD_PORT=8125
AIRFLOW__METRICS__STATSD_PREFIX=airflow
AIRFLOW__METRICS__STATSD_IPV6=True
Start an Airflow component that initializes metrics, for example a worker.
Expected: StatsD client is initialized with IPv6 enabled.
Actual: Airflow logs:
Could not configure StatsClient: [Errno -5] No address associated with
hostname, using NoStatsLogger instead.
and metrics are not emitted.
This can also be demonstrated with a custom test StatsD client that records
received constructor arguments: the ipv6 value is passed as the fourth
positional argument instead of the ipv6 keyword argument.
Workaround
We are currently working around this by overriding the StatsD client:
- name: AIRFLOW__METRICS__STATSD_CUSTOM_CLIENT_PATH
value: "settings.metrics.ipv6_statsd_client.IPv6StatsClient"
The custom client detects the Airflow positional-argument behavior and
forwards ipv6=True to the parent statsd.StatsClient as a keyword argument:
class IPv6StatsClient(statsd.StatsClient):
def __init__(
self,
host: str = "localhost",
port: int = 8125,
prefix: str | None = None,
maxudpsize: int = 512,
ipv6: bool = False,
) -> None:
# Airflow passes ipv6 as the 4th positional argument,
# which lands in maxudpsize for statsd.StatsClient.
if isinstance(maxudpsize, bool):
ipv6 = maxudpsize
maxudpsize = 512
super().__init__(
host=host,
port=port,
prefix=prefix,
maxudpsize=maxudpsize,
ipv6=True,
)
This workaround confirms that the same StatsD endpoint works once the
underlying statsd.StatsClient is initialized with IPv6 enabled.
Suggested fix
Pass arguments to the StatsD client by keyword instead of positionally:
statsd = stats_class(
host=host,
port=port,
prefix=prefix,
ipv6=ipv6,
)
This should make [metrics] statsd_ipv6 = True work as documented for the
default statsd.StatsClient.
A regression test could assert that when ipv6=True is passed to
get_statsd_logger(), the configured StatsD client receives ipv6=True as the
ipv6 argument, not as maxudpsize.
Related context
This appears related to the previous IPv6 StatsD support change:
https://github.com/apache/airflow/pull/42625
That PR added an option to enable IPv6 address resolution for the StatsD
host, but the current positional call appears to prevent the option from taking
effect with the default statsd.StatsClient.
### What you think should happen instead?
_No response_
### Operating System
_No response_
### Deployment
None
### Apache Airflow Provider(s)
_No response_
### Versions of Apache Airflow Providers
_No response_
### Official Helm Chart version
1.22.0 (latest released)
### Kubernetes Version
_No response_
### Helm Chart configuration
_No response_
### Docker Image customizations
_No response_
### Anything else?
_No response_
### Are you willing to submit PR?
- [x] Yes I am willing to submit a PR!
### Code of Conduct
- [x] I agree to follow this project's [Code of
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]