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]

Reply via email to