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

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

49 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 .base_stats_logger import NoStatsLogger 

26 

27if TYPE_CHECKING: 

28 from .base_stats_logger import StatsLogger 

29 

30log = logging.getLogger(__name__) 

31 

32 

33class _Stats(type): 

34 factory: Callable[[], StatsLogger | NoStatsLogger] | None = None 

35 instance: StatsLogger | NoStatsLogger | None = None 

36 

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

38 factory = type.__getattribute__(cls, "factory") 

39 instance = type.__getattribute__(cls, "instance") 

40 

41 if instance is None: 

42 if factory is None: 

43 factory = NoStatsLogger 

44 type.__setattr__(cls, "factory", factory) 

45 

46 try: 

47 instance = factory() 

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

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

50 instance = NoStatsLogger() 

51 

52 type.__setattr__(cls, "instance", instance) 

53 

54 return getattr(instance, name) 

55 

56 def initialize(cls, *, is_statsd_datadog_enabled: bool, is_statsd_on: bool, is_otel_on: bool) -> None: 

57 type.__setattr__(cls, "factory", None) 

58 type.__setattr__(cls, "instance", None) 

59 

60 if is_statsd_datadog_enabled: 

61 from airflow.observability.metrics import datadog_logger 

62 

63 # Datadog needs the cls param, so wrap it into a 0-arg factory. 

64 factory = lambda: datadog_logger.get_dogstatsd_logger(cls) 

65 elif is_statsd_on: 

66 from airflow.observability.metrics import statsd_logger 

67 

68 factory = statsd_logger.get_statsd_logger 

69 elif is_otel_on: 

70 from airflow.observability.metrics import otel_logger 

71 

72 factory = otel_logger.get_otel_logger 

73 else: 

74 factory = NoStatsLogger 

75 

76 type.__setattr__(cls, "factory", factory) 

77 

78 @classmethod 

79 def get_constant_tags(cls, *, tags_in_string: str | None) -> list[str]: 

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

81 if not tags_in_string: 

82 return [] 

83 return tags_in_string.split(",") 

84 

85 

86if TYPE_CHECKING: 

87 Stats: StatsLogger 

88else: 

89 

90 class Stats(metaclass=_Stats): 

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