Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/opentelemetry/trace/propagation/tracecontext.py: 30%

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

56 statements  

1# Copyright The OpenTelemetry Authors 

2# SPDX-License-Identifier: Apache-2.0 

3# 

4import logging 

5import re 

6 

7from opentelemetry import trace 

8from opentelemetry.context.context import Context 

9from opentelemetry.propagators import textmap 

10from opentelemetry.trace import format_span_id, format_trace_id 

11from opentelemetry.trace.span import ( 

12 _TRACECONTEXT_MAXIMUM_TRACESTATE_LENGTH, 

13 TraceState, 

14) 

15 

16_logger = logging.getLogger(__name__) 

17 

18 

19class TraceContextTextMapPropagator(textmap.TextMapPropagator): 

20 """Extracts and injects using w3c TraceContext's headers.""" 

21 

22 _TRACEPARENT_HEADER_NAME = "traceparent" 

23 _TRACESTATE_HEADER_NAME = "tracestate" 

24 _TRACEPARENT_HEADER_FORMAT = "^[ \t]*([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})" + "(-.*)?[ \t]*$" 

25 _TRACEPARENT_HEADER_FORMAT_RE = re.compile(_TRACEPARENT_HEADER_FORMAT) 

26 

27 def extract( 

28 self, 

29 carrier: textmap.CarrierT, 

30 context: Context | None = None, 

31 getter: textmap.Getter[textmap.CarrierT] = textmap.default_getter, 

32 ) -> Context: 

33 """Extracts SpanContext from the carrier. 

34 

35 See `opentelemetry.propagators.textmap.TextMapPropagator.extract` 

36 """ 

37 if context is None: 

38 context = Context() 

39 

40 header = getter.get(carrier, self._TRACEPARENT_HEADER_NAME) 

41 

42 if not header: 

43 return context 

44 

45 match = re.search(self._TRACEPARENT_HEADER_FORMAT_RE, header[0]) 

46 if not match: 

47 return context 

48 

49 version: str = match.group(1) 

50 trace_id: str = match.group(2) 

51 span_id: str = match.group(3) 

52 trace_flags: str = match.group(4) 

53 

54 if trace_id == "0" * 32 or span_id == "0" * 16: 

55 return context 

56 

57 if version == "00": 

58 if match.group(5): # type: ignore 

59 return context 

60 if version == "ff": 

61 return context 

62 

63 tracestate_headers = getter.get(carrier, self._TRACESTATE_HEADER_NAME) 

64 if tracestate_headers is None: 

65 tracestate = None 

66 elif ( 

67 # multiple header fields are combined with "," (RFC 9110, section 5.3) 

68 sum(len(header) for header in tracestate_headers) + len(tracestate_headers) - 1 

69 > _TRACECONTEXT_MAXIMUM_TRACESTATE_LENGTH 

70 ): 

71 _logger.warning( 

72 "tracestate header exceeded the maximum length of %d characters", 

73 _TRACECONTEXT_MAXIMUM_TRACESTATE_LENGTH, 

74 ) 

75 tracestate = None 

76 else: 

77 tracestate = TraceState.from_header(tracestate_headers) 

78 

79 span_context = trace.SpanContext( 

80 trace_id=int(trace_id, 16), 

81 span_id=int(span_id, 16), 

82 is_remote=True, 

83 trace_flags=trace.TraceFlags(int(trace_flags, 16)), 

84 trace_state=tracestate, 

85 ) 

86 return trace.set_span_in_context(trace.NonRecordingSpan(span_context), context) 

87 

88 def inject( 

89 self, 

90 carrier: textmap.CarrierT, 

91 context: Context | None = None, 

92 setter: textmap.Setter[textmap.CarrierT] = textmap.default_setter, 

93 ) -> None: 

94 """Injects SpanContext into the carrier. 

95 

96 See `opentelemetry.propagators.textmap.TextMapPropagator.inject` 

97 """ 

98 span = trace.get_current_span(context) 

99 span_context = span.get_span_context() 

100 if span_context == trace.INVALID_SPAN_CONTEXT: 

101 return 

102 traceparent_string = f"00-{format_trace_id(span_context.trace_id)}-{format_span_id(span_context.span_id)}-{span_context.trace_flags:02x}" 

103 setter.set(carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string) 

104 if span_context.trace_state: 

105 tracestate_string = span_context.trace_state.to_header() 

106 setter.set(carrier, self._TRACESTATE_HEADER_NAME, tracestate_string) 

107 

108 @property 

109 def fields(self) -> set[str]: 

110 """Returns a set with the fields set in `inject`. 

111 

112 See 

113 `opentelemetry.propagators.textmap.TextMapPropagator.fields` 

114 """ 

115 return {self._TRACEPARENT_HEADER_NAME, self._TRACESTATE_HEADER_NAME}