This is an automated email from the ASF dual-hosted git repository.
amoghrajesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new fe30279b379 Fix scheduler crash with InvalidStatsNameException for
non-ASCII DAG names when OTel metrics enabled (#68023)
fe30279b379 is described below
commit fe30279b379e7884c66c01bb0db9da3589856278
Author: Salil Agrawal <[email protected]>
AuthorDate: Mon Jun 8 20:45:19 2026 +0530
Fix scheduler crash with InvalidStatsNameException for non-ASCII DAG names
when OTel metrics enabled (#68023)
---
.../observability/metrics/otel_logger.py | 7 ++++++-
.../observability/metrics/test_otel_logger.py | 23 +++++++++++++++++-----
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git
a/shared/observability/src/airflow_shared/observability/metrics/otel_logger.py
b/shared/observability/src/airflow_shared/observability/metrics/otel_logger.py
index 8d25b23372a..4bd6f116683 100644
---
a/shared/observability/src/airflow_shared/observability/metrics/otel_logger.py
+++
b/shared/observability/src/airflow_shared/observability/metrics/otel_logger.py
@@ -34,6 +34,7 @@ from opentelemetry.sdk.metrics.view import
ExponentialBucketHistogramAggregation
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from ..common import get_otel_data_exporter
+from ..exceptions import InvalidStatsNameException
from ..otel_env_config import load_metrics_env_config
from .protocols import Timer
from .validators import (
@@ -103,7 +104,11 @@ def name_is_otel_safe(prefix: str, name: str) -> bool:
Legal names are defined here:
https://opentelemetry.io/docs/reference/specification/metrics/api/#instrument-name-syntax
"""
- return bool(stat_name_otel_handler(prefix, name,
max_length=OTEL_NAME_MAX_LENGTH))
+ try:
+ return bool(stat_name_otel_handler(prefix, name,
max_length=OTEL_NAME_MAX_LENGTH))
+ except InvalidStatsNameException:
+ log.warning("Invalid stat name: %s.%s.", prefix, name)
+ return False
def _type_as_str(obj: Instrument) -> str:
diff --git
a/shared/observability/tests/observability/metrics/test_otel_logger.py
b/shared/observability/tests/observability/metrics/test_otel_logger.py
index 21d27789def..c5312f509bd 100644
--- a/shared/observability/tests/observability/metrics/test_otel_logger.py
+++ b/shared/observability/tests/observability/metrics/test_otel_logger.py
@@ -28,7 +28,6 @@ from opentelemetry.metrics import MeterProvider
from opentelemetry.sdk.metrics.view import
ExponentialBucketHistogramAggregation, View
from airflow_shared.observability.common import get_otel_data_exporter
-from airflow_shared.observability.exceptions import InvalidStatsNameException
from airflow_shared.observability.metrics.otel_logger import (
OTEL_NAME_MAX_LENGTH,
UP_DOWN_COUNTERS,
@@ -98,15 +97,29 @@ class TestOtelMetrics:
],
],
)
- def test_invalid_stat_names_are_caught(self, invalid_stat_combo):
+ def test_invalid_stat_names_are_skipped(self, invalid_stat_combo):
prefix = invalid_stat_combo[0]
name = invalid_stat_combo[1]
self.stats.prefix = prefix
- with pytest.raises(InvalidStatsNameException):
- self.stats.incr(name)
+ result = self.stats.incr(name)
+
+ assert result is None
+ self.meter.get_meter().create_counter.assert_not_called()
+
+ @pytest.mark.parametrize(
+ "stat",
+ [
+ "dag.my_dag.preço_task.scheduled_duration",
+ "dag.my_dag.tâche_principale.duration",
+ "dag.my_dag.aufgäbe.duration",
+ ],
+ )
+ def test_non_ascii_stat_names_are_skipped_without_raising(self, stat):
+ result = self.stats.incr(stat)
- self.meter.assert_not_called()
+ assert result is None
+ self.meter.get_meter().create_counter.assert_not_called()
def test_old_name_exception_works(self, caplog):
name =
"task_instance_created_OperatorNameWhichIsSuperLongAndExceedsTheOpenTelemetryCharacterLimit/task_instance_created_OperatorNameWhichIsSuperLongAndExceedsTheOpenTelemetryCharacterLimit/task_instance_created_OperatorNameWhichIsSuperLongAndExceedsTheOpenTelemetryCharacterLimit"