Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/airflow/sdk/observability/stats.py: 56%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

45 statements  

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. 

18from __future__ import annotations 

19 

20import logging 

21import socket 

22from collections.abc import Callable 

23from typing import TYPE_CHECKING 

24 

25from airflow.sdk._shared.observability.metrics.base_stats_logger import NoStatsLogger 

26from airflow.sdk.configuration import conf 

27 

28if TYPE_CHECKING: 

29 from airflow.sdk._shared.observability.metrics.base_stats_logger import StatsLogger 

30 

31log = logging.getLogger(__name__) 

32 

33 

34class _Stats(type): 

35 factory: Callable 

36 instance: StatsLogger | NoStatsLogger | None = None 

37 

38 def __getattr__(cls, name: str) -> str: 

39 if not cls.instance: 

40 try: 

41 cls.instance = cls.factory() 

42 except (socket.gaierror, ImportError) as e: 

43 log.error("Could not configure StatsClient: %s, using NoStatsLogger instead.", e) 

44 cls.instance = NoStatsLogger() 

45 return getattr(cls.instance, name) 

46 

47 def __init__(cls, *args, **kwargs) -> None: 

48 super().__init__(cls) 

49 if not hasattr(cls.__class__, "factory"): 

50 is_datadog_enabled_defined = conf.has_option("metrics", "statsd_datadog_enabled") 

51 if is_datadog_enabled_defined and conf.getboolean("metrics", "statsd_datadog_enabled"): 

52 from airflow.sdk.observability.metrics import datadog_logger 

53 

54 cls.__class__.factory = datadog_logger.get_dogstatsd_logger 

55 elif conf.getboolean("metrics", "statsd_on"): 

56 from airflow.sdk.observability.metrics import statsd_logger 

57 

58 cls.__class__.factory = statsd_logger.get_statsd_logger 

59 elif conf.getboolean("metrics", "otel_on"): 

60 from airflow.sdk.observability.metrics import otel_logger 

61 

62 cls.__class__.factory = otel_logger.get_otel_logger 

63 else: 

64 cls.__class__.factory = NoStatsLogger 

65 

66 @classmethod 

67 def get_constant_tags(cls) -> list[str]: 

68 """Get constant DataDog tags to add to all stats.""" 

69 tags_in_string = conf.get("metrics", "statsd_datadog_tags", fallback=None) 

70 if not tags_in_string: 

71 return [] 

72 return tags_in_string.split(",") 

73 

74 

75if TYPE_CHECKING: 

76 Stats: StatsLogger 

77else: 

78 

79 class Stats(metaclass=_Stats): 

80 """Empty class for Stats - we use metaclass to inject the right one."""