Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/opentelemetry/context/__init__.py: 62%

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

42 statements  

1# Copyright The OpenTelemetry Authors 

2# SPDX-License-Identifier: Apache-2.0 

3 

4from __future__ import annotations 

5 

6import logging 

7from contextvars import Token 

8from os import environ 

9from uuid import uuid4 

10 

11# pylint: disable=wrong-import-position 

12from opentelemetry.context.context import Context, _RuntimeContext # noqa 

13from opentelemetry.environment_variables import OTEL_PYTHON_CONTEXT 

14from opentelemetry.util._importlib_metadata import entry_points 

15 

16logger = logging.getLogger(__name__) 

17 

18 

19def _load_runtime_context() -> _RuntimeContext: 

20 """Initialize the RuntimeContext 

21 

22 Returns: 

23 An instance of RuntimeContext. 

24 """ 

25 

26 # FIXME use a better implementation of a configuration manager 

27 # to avoid having to get configuration values straight from 

28 # environment variables 

29 default_context = "contextvars_context" 

30 

31 configured_context = environ.get(OTEL_PYTHON_CONTEXT, default_context) # type: str 

32 

33 try: 

34 return next( # type: ignore 

35 iter( # type: ignore 

36 entry_points( # type: ignore 

37 group="opentelemetry_context", 

38 name=configured_context, 

39 ) 

40 ) 

41 ).load()() 

42 except Exception: # pylint: disable=broad-exception-caught 

43 logger.exception( 

44 "Failed to load context: %s, fallback to %s", 

45 configured_context, 

46 default_context, 

47 ) 

48 return next( # type: ignore 

49 iter( # type: ignore 

50 entry_points( # type: ignore 

51 group="opentelemetry_context", 

52 name=default_context, 

53 ) 

54 ) 

55 ).load()() 

56 

57 

58_RUNTIME_CONTEXT = _load_runtime_context() 

59 

60 

61def create_key(keyname: str) -> str: 

62 """To allow cross-cutting concern to control access to their local state, 

63 the RuntimeContext API provides a function which takes a keyname as input, 

64 and returns a unique key. 

65 Args: 

66 keyname: The key name is for debugging purposes and is not required to be unique. 

67 Returns: 

68 A unique string representing the newly created key. 

69 """ 

70 return keyname + "-" + str(uuid4()) 

71 

72 

73def get_value(key: str, context: Context | None = None) -> object: 

74 """To access the local state of a concern, the RuntimeContext API 

75 provides a function which takes a context and a key as input, 

76 and returns a value. 

77 

78 Args: 

79 key: The key of the value to retrieve. 

80 context: The context from which to retrieve the value, if None, the current context is used. 

81 

82 Returns: 

83 The value associated with the key. 

84 """ 

85 return context.get(key) if context is not None else get_current().get(key) 

86 

87 

88def set_value( 

89 key: str, value: object, context: Context | None = None 

90) -> Context: 

91 """To record the local state of a cross-cutting concern, the 

92 RuntimeContext API provides a function which takes a context, a 

93 key, and a value as input, and returns an updated context 

94 which contains the new value. 

95 

96 Args: 

97 key: The key of the entry to set. 

98 value: The value of the entry to set. 

99 context: The context to copy, if None, the current context is used. 

100 

101 Returns: 

102 A new `Context` containing the value set. 

103 """ 

104 if context is None: 

105 context = get_current() 

106 new_values = context.copy() 

107 new_values[key] = value 

108 return Context(new_values) 

109 

110 

111def get_current() -> Context: 

112 """To access the context associated with program execution, 

113 the Context API provides a function which takes no arguments 

114 and returns a Context. 

115 

116 Returns: 

117 The current `Context` object. 

118 """ 

119 return _RUNTIME_CONTEXT.get_current() 

120 

121 

122def attach(context: Context) -> Token[Context]: 

123 """Associates a Context with the caller's current execution unit. Returns 

124 a token that can be used to restore the previous Context. 

125 

126 Args: 

127 context: The Context to set as current. 

128 

129 Returns: 

130 A token that can be used with `detach` to reset the context. 

131 """ 

132 return _RUNTIME_CONTEXT.attach(context) 

133 

134 

135def detach(token: Token[Context]) -> None: 

136 """Resets the Context associated with the caller's current execution unit 

137 to the value it had before attaching a specified Context. 

138 

139 Args: 

140 token: The Token that was returned by a previous call to attach a Context. 

141 """ 

142 try: 

143 _RUNTIME_CONTEXT.detach(token) 

144 except Exception: # pylint: disable=broad-exception-caught 

145 logger.exception("Failed to detach context") 

146 

147 

148# FIXME This is a temporary location for the suppress instrumentation key. 

149# Once the decision around how to suppress instrumentation is made in the 

150# spec, this key should be moved accordingly. 

151_ON_EMIT_RECURSION_COUNT_KEY = create_key("on_emit_recursion_count") 

152_SUPPRESS_INSTRUMENTATION_KEY = create_key("suppress_instrumentation") 

153_SUPPRESS_HTTP_INSTRUMENTATION_KEY = create_key( 

154 "suppress_http_instrumentation" 

155) 

156 

157__all__ = [ 

158 "Context", 

159 "attach", 

160 "create_key", 

161 "detach", 

162 "get_current", 

163 "get_value", 

164 "set_value", 

165]