stats.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #
  2. # Licensed to the Apache Software Foundation (ASF) under one
  3. # or more contributor license agreements. See the NOTICE file
  4. # distributed with this work for additional information
  5. # regarding copyright ownership. The ASF licenses this file
  6. # to you under the Apache License, Version 2.0 (the
  7. # "License"); you may not use this file except in compliance
  8. # with the License. You may obtain a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  12. # Unless required by applicable law or agreed to in writing,
  13. # software distributed under the License is distributed on an
  14. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. # KIND, either express or implied. See the License for the
  16. # specific language governing permissions and limitations
  17. # under the License.
  18. from __future__ import annotations
  19. import logging
  20. import socket
  21. from typing import TYPE_CHECKING, Callable
  22. from airflow.configuration import conf
  23. from airflow.metrics.base_stats_logger import NoStatsLogger
  24. if TYPE_CHECKING:
  25. from airflow.metrics.base_stats_logger import StatsLogger
  26. log = logging.getLogger(__name__)
  27. class _Stats(type):
  28. factory: Callable
  29. instance: StatsLogger | NoStatsLogger | None = None
  30. def __getattr__(cls, name: str) -> str:
  31. if not cls.instance:
  32. try:
  33. cls.instance = cls.factory()
  34. except (socket.gaierror, ImportError) as e:
  35. log.error("Could not configure StatsClient: %s, using NoStatsLogger instead.", e)
  36. cls.instance = NoStatsLogger()
  37. return getattr(cls.instance, name)
  38. def __init__(cls, *args, **kwargs) -> None:
  39. super().__init__(cls)
  40. if not hasattr(cls.__class__, "factory"):
  41. is_datadog_enabled_defined = conf.has_option("metrics", "statsd_datadog_enabled")
  42. if is_datadog_enabled_defined and conf.getboolean("metrics", "statsd_datadog_enabled"):
  43. from airflow.metrics import datadog_logger
  44. cls.__class__.factory = datadog_logger.get_dogstatsd_logger
  45. elif conf.getboolean("metrics", "statsd_on"):
  46. from airflow.metrics import statsd_logger
  47. cls.__class__.factory = statsd_logger.get_statsd_logger
  48. elif conf.getboolean("metrics", "otel_on"):
  49. from airflow.metrics import otel_logger
  50. cls.__class__.factory = otel_logger.get_otel_logger
  51. else:
  52. cls.__class__.factory = NoStatsLogger
  53. @classmethod
  54. def get_constant_tags(cls) -> list[str]:
  55. """Get constant DataDog tags to add to all stats."""
  56. tags_in_string = conf.get("metrics", "statsd_datadog_tags", fallback=None)
  57. if not tags_in_string:
  58. return []
  59. return tags_in_string.split(",")
  60. if TYPE_CHECKING:
  61. Stats: StatsLogger
  62. else:
  63. class Stats(metaclass=_Stats):
  64. """Empty class for Stats - we use metaclass to inject the right one."""