# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from __future__ import annotations import logging import socket from typing import TYPE_CHECKING, Callable from airflow.configuration import conf from airflow.metrics.base_stats_logger import NoStatsLogger if TYPE_CHECKING: from airflow.metrics.base_stats_logger import StatsLogger log = logging.getLogger(__name__) class _Stats(type): factory: Callable instance: StatsLogger | NoStatsLogger | None = None def __getattr__(cls, name: str) -> str: if not cls.instance: try: cls.instance = cls.factory() except (socket.gaierror, ImportError) as e: log.error("Could not configure StatsClient: %s, using NoStatsLogger instead.", e) cls.instance = NoStatsLogger() return getattr(cls.instance, name) def __init__(cls, *args, **kwargs) -> None: super().__init__(cls) if not hasattr(cls.__class__, "factory"): is_datadog_enabled_defined = conf.has_option("metrics", "statsd_datadog_enabled") if is_datadog_enabled_defined and conf.getboolean("metrics", "statsd_datadog_enabled"): from airflow.metrics import datadog_logger cls.__class__.factory = datadog_logger.get_dogstatsd_logger elif conf.getboolean("metrics", "statsd_on"): from airflow.metrics import statsd_logger cls.__class__.factory = statsd_logger.get_statsd_logger elif conf.getboolean("metrics", "otel_on"): from airflow.metrics import otel_logger cls.__class__.factory = otel_logger.get_otel_logger else: cls.__class__.factory = NoStatsLogger @classmethod def get_constant_tags(cls) -> list[str]: """Get constant DataDog tags to add to all stats.""" tags_in_string = conf.get("metrics", "statsd_datadog_tags", fallback=None) if not tags_in_string: return [] return tags_in_string.split(",") if TYPE_CHECKING: Stats: StatsLogger else: class Stats(metaclass=_Stats): """Empty class for Stats - we use metaclass to inject the right one."""