We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add xray propagators that prioritizes xray environment variable
Similar to [this](https://github.com/open-telemetry/opentelemetry-java-contrib/pull/1032).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """
16 AWS X-Ray Propagator
17 --------------------
18 
19 The **AWS X-Ray Propagator** provides a propagator that when used, adds a `trace
20 header`_ to outgoing traces that is compatible with the AWS X-Ray backend
21 service. This allows the trace context to be propagated when a trace spans
22 multiple AWS services.
23 
24 The same propagator setup is used to extract a context sent by external systems
25 so that child span have the correct parent context.
26 
27 **NOTE**: Because the parent context parsed from the ``X-Amzn-Trace-Id`` header
28 assumes the context is _not_ sampled by default, users should make sure to add
29 ``Sampled=1`` to their ``X-Amzn-Trace-Id`` headers so that the child spans are
30 sampled.
31 
32 Usage
33 -----
34 
35 Use the provided AWS X-Ray Propagator to inject the necessary context into
36 traces sent to external systems.
37 
38 This can be done by either setting this environment variable:
39 
40 ::
41 
42     export OTEL_PROPAGATORS = xray
43 
44 
45 Or by setting this propagator in your instrumented application:
46 
47 .. code-block:: python
48 
49     from opentelemetry.propagate import set_global_textmap
50     from opentelemetry.propagators.aws import AwsXRayPropagator
51 
52     set_global_textmap(AwsXRayPropagator())
53 
54 API
55 ---
56 .. _trace header: https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader
57 """
58 
59 import logging
60 import typing
61 
62 from opentelemetry import trace
63 from opentelemetry.context import Context
64 from opentelemetry.propagators.textmap import (
65     CarrierT,
66     Getter,
67     Setter,
68     TextMapPropagator,
69     default_getter,
70     default_setter,
71 )
72 
73 TRACE_HEADER_KEY = "X-Amzn-Trace-Id"
74 KV_PAIR_DELIMITER = ";"
75 KEY_AND_VALUE_DELIMITER = "="
76 
77 TRACE_ID_KEY = "Root"
78 TRACE_ID_LENGTH = 35
79 TRACE_ID_VERSION = "1"
80 TRACE_ID_DELIMITER = "-"
81 TRACE_ID_DELIMITER_INDEX_1 = 1
82 TRACE_ID_DELIMITER_INDEX_2 = 10
83 TRACE_ID_FIRST_PART_LENGTH = 8
84 
85 PARENT_ID_KEY = "Parent"
86 PARENT_ID_LENGTH = 16
87 
88 SAMPLED_FLAG_KEY = "Sampled"
89 SAMPLED_FLAG_LENGTH = 1
90 IS_SAMPLED = "1"
91 NOT_SAMPLED = "0"
92 
93 
94 _logger = logging.getLogger(__name__)
95 
96 
97 class AwsParseTraceHeaderError(Exception):
98     def __init__(self, message):
99         super().__init__()
100         self.message = message
101 
102 
103 class AwsXRayPropagator(TextMapPropagator):
104     """Propagator for the AWS X-Ray Trace Header propagation protocol.
105 
106     See:
107     https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader
108     """
109 
110     # AWS
111 
112     def extract(
113         self,
114         carrier: CarrierT,
115         context: typing.Optional[Context] = None,
116         getter: Getter[CarrierT] = default_getter,
117     ) -> Context:
118         if context is None:
119             context = Context()
120 
121         trace_header_list = getter.get(carrier, TRACE_HEADER_KEY)
122 
123         if not trace_header_list or len(trace_header_list) != 1:
124             return context
125 
126         trace_header = trace_header_list[0]
127 
128         if not trace_header:
129             return context
130 
131         try:
132             (
133                 trace_id,
134                 span_id,
135                 sampled,
136             ) = AwsXRayPropagator._extract_span_properties(trace_header)
137         except AwsParseTraceHeaderError as err:
138             _logger.debug(err.message)
139             return context
140 
141         options = 0
142         if sampled:
143             options |= trace.TraceFlags.SAMPLED
144 
145         span_context = trace.SpanContext(
146             trace_id=trace_id,
147             span_id=span_id,
148             is_remote=True,
149             trace_flags=trace.TraceFlags(options),
150             trace_state=trace.TraceState(),
151         )
152 
153         if not span_context.is_valid:
154             _logger.debug(
155                 "Invalid Span Extracted. Inserting INVALID span into provided context."
156             )
157             return context
158 
159         return trace.set_span_in_context(
160             trace.NonRecordingSpan(span_context), context=context
161         )
162 
163     @staticmethod
164     def _extract_span_properties(trace_header):
165         trace_id = trace.INVALID_TRACE_ID
166         span_id = trace.INVALID_SPAN_ID
167         sampled = False
168 
169         for kv_pair_str in trace_header.split(KV_PAIR_DELIMITER):
170             try:
171                 key_str, value_str = kv_pair_str.split(KEY_AND_VALUE_DELIMITER)
172                 key, value = key_str.strip(), value_str.strip()
173             except ValueError as ex:
174                 raise AwsParseTraceHeaderError(
175                     (
176                         "Error parsing X-Ray trace header. Invalid key value pair: %s. Returning INVALID span context.",
177                         kv_pair_str,
178                     )
179                 ) from ex
180             if key == TRACE_ID_KEY:
181                 if not AwsXRayPropagator._validate_trace_id(value):
182                     raise AwsParseTraceHeaderError(
183                         (
184                             "Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
185                             TRACE_HEADER_KEY,
186                             trace_header,
187                         )
188                     )
189 
190                 try:
191                     trace_id = AwsXRayPropagator._parse_trace_id(value)
192                 except ValueError as ex:
193                     raise AwsParseTraceHeaderError(
194                         (
195                             "Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
196                             TRACE_HEADER_KEY,
197                             trace_header,
198                         )
199                     ) from ex
200             elif key == PARENT_ID_KEY:
201                 if not AwsXRayPropagator._validate_span_id(value):
202                     raise AwsParseTraceHeaderError(
203                         (
204                             "Invalid ParentId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
205                             TRACE_HEADER_KEY,
206                             trace_header,
207                         )
208                     )
209 
210                 try:
211                     span_id = AwsXRayPropagator._parse_span_id(value)
212                 except ValueError as ex:
213                     raise AwsParseTraceHeaderError(
214                         (
215                             "Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
216                             TRACE_HEADER_KEY,
217                             trace_header,
218                         )
219                     ) from ex
220             elif key == SAMPLED_FLAG_KEY:
221                 if not AwsXRayPropagator._validate_sampled_flag(value):
222                     raise AwsParseTraceHeaderError(
223                         (
224                             "Invalid Sampling flag in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.",
225                             TRACE_HEADER_KEY,
226                             trace_header,
227                         )
228                     )
229 
230                 sampled = AwsXRayPropagator._parse_sampled_flag(value)
231 
232         return trace_id, span_id, sampled
233 
234     @staticmethod
235     def _validate_trace_id(trace_id_str):
236         return (
237             len(trace_id_str) == TRACE_ID_LENGTH
238             and trace_id_str.startswith(TRACE_ID_VERSION)
239             and trace_id_str[TRACE_ID_DELIMITER_INDEX_1] == TRACE_ID_DELIMITER
240             and trace_id_str[TRACE_ID_DELIMITER_INDEX_2] == TRACE_ID_DELIMITER
241         )
242 
243     @staticmethod
244     def _parse_trace_id(trace_id_str):
245         timestamp_subset = trace_id_str[
246             TRACE_ID_DELIMITER_INDEX_1 + 1 : TRACE_ID_DELIMITER_INDEX_2
247         ]
248         unique_id_subset = trace_id_str[
249             TRACE_ID_DELIMITER_INDEX_2 + 1 : TRACE_ID_LENGTH
250         ]
251         return int(timestamp_subset + unique_id_subset, 16)
252 
253     @staticmethod
254     def _validate_span_id(span_id_str):
255         return len(span_id_str) == PARENT_ID_LENGTH
256 
257     @staticmethod
258     def _parse_span_id(span_id_str):
259         return int(span_id_str, 16)
260 
261     @staticmethod
262     def _validate_sampled_flag(sampled_flag_str):
263         return len(
264             sampled_flag_str
265         ) == SAMPLED_FLAG_LENGTH and sampled_flag_str in (
266             IS_SAMPLED,
267             NOT_SAMPLED,
268         )
269 
270     @staticmethod
271     def _parse_sampled_flag(sampled_flag_str):
272         return sampled_flag_str[0] == IS_SAMPLED
273 
274     def inject(
275         self,
276         carrier: CarrierT,
277         context: typing.Optional[Context] = None,
278         setter: Setter[CarrierT] = default_setter,
279     ) -> None:
280         span = trace.get_current_span(context=context)
281 
282         span_context = span.get_span_context()
283         if not span_context.is_valid:
284             return
285 
286         otel_trace_id = f"{span_context.trace_id:032x}"
287         xray_trace_id = TRACE_ID_DELIMITER.join(
288             [
289                 TRACE_ID_VERSION,
290                 otel_trace_id[:TRACE_ID_FIRST_PART_LENGTH],
291                 otel_trace_id[TRACE_ID_FIRST_PART_LENGTH:],
292             ]
293         )
294 
295         parent_id = f"{span_context.span_id:016x}"
296 
297         sampling_flag = (
298             IS_SAMPLED
299             if span_context.trace_flags & trace.TraceFlags.SAMPLED
300             else NOT_SAMPLED
301         )
302 
303         # TODO: Add OT trace state to the X-Ray trace header
304 
305         trace_header = KV_PAIR_DELIMITER.join(
306             [
307                 KEY_AND_VALUE_DELIMITER.join([key, value])
308                 for key, value in [
309                     (TRACE_ID_KEY, xray_trace_id),
310                     (PARENT_ID_KEY, parent_id),
311                     (SAMPLED_FLAG_KEY, sampling_flag),
312                 ]
313             ]
314         )
315 
316         setter.set(
317             carrier,
318             TRACE_HEADER_KEY,
319             trace_header,
320         )
321 
322     @property
323     def fields(self):
324         """Returns a set with the fields set in `inject`."""
325 
326         return {TRACE_HEADER_KEY}
327
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py
--- a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py
+++ b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py
@@ -58,6 +58,7 @@
 
 import logging
 import typing
+from os import environ
 
 from opentelemetry import trace
 from opentelemetry.context import Context
@@ -71,6 +72,7 @@
 )
 
 TRACE_HEADER_KEY = "X-Amzn-Trace-Id"
+AWS_TRACE_HEADER_ENV_KEY = "_X_AMZN_TRACE_ID"
 KV_PAIR_DELIMITER = ";"
 KEY_AND_VALUE_DELIMITER = "="
 
@@ -324,3 +326,33 @@
         """Returns a set with the fields set in `inject`."""
 
         return {TRACE_HEADER_KEY}
+
+
+class AwsXrayLambdaPropagator(AwsXRayPropagator):
+    """Implementation of the AWS X-Ray Trace Header propagation protocol but
+    with special handling for Lambda's ``_X_AMZN_TRACE_ID` environment
+    variable.
+    """
+
+    def extract(
+        self,
+        carrier: CarrierT,
+        context: typing.Optional[Context] = None,
+        getter: Getter[CarrierT] = default_getter,
+    ) -> Context:
+
+        xray_context = super().extract(carrier, context=context, getter=getter)
+
+        if trace.get_current_span(context=context).get_span_context().is_valid:
+            return xray_context
+
+        trace_header = environ.get(AWS_TRACE_HEADER_ENV_KEY)
+
+        if trace_header is None:
+            return xray_context
+
+        return super().extract(
+            {TRACE_HEADER_KEY: trace_header},
+            context=xray_context,
+            getter=getter,
+        )

{"golden_diff": "diff --git a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py\n--- a/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py\n+++ b/propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py\n@@ -58,6 +58,7 @@\n \n import logging\n import typing\n+from os import environ\n \n from opentelemetry import trace\n from opentelemetry.context import Context\n@@ -71,6 +72,7 @@\n )\n \n TRACE_HEADER_KEY = \"X-Amzn-Trace-Id\"\n+AWS_TRACE_HEADER_ENV_KEY = \"_X_AMZN_TRACE_ID\"\n KV_PAIR_DELIMITER = \";\"\n KEY_AND_VALUE_DELIMITER = \"=\"\n \n@@ -324,3 +326,33 @@\n         \"\"\"Returns a set with the fields set in `inject`.\"\"\"\n \n         return {TRACE_HEADER_KEY}\n+\n+\n+class AwsXrayLambdaPropagator(AwsXRayPropagator):\n+    \"\"\"Implementation of the AWS X-Ray Trace Header propagation protocol but\n+    with special handling for Lambda's ``_X_AMZN_TRACE_ID` environment\n+    variable.\n+    \"\"\"\n+\n+    def extract(\n+        self,\n+        carrier: CarrierT,\n+        context: typing.Optional[Context] = None,\n+        getter: Getter[CarrierT] = default_getter,\n+    ) -> Context:\n+\n+        xray_context = super().extract(carrier, context=context, getter=getter)\n+\n+        if trace.get_current_span(context=context).get_span_context().is_valid:\n+            return xray_context\n+\n+        trace_header = environ.get(AWS_TRACE_HEADER_ENV_KEY)\n+\n+        if trace_header is None:\n+            return xray_context\n+\n+        return super().extract(\n+            {TRACE_HEADER_KEY: trace_header},\n+            context=xray_context,\n+            getter=getter,\n+        )\n", "issue": "Add xray propagators that prioritizes xray environment variable\nSimilar to [this](https://github.com/open-telemetry/opentelemetry-java-contrib/pull/1032).\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nAWS X-Ray Propagator\n--------------------\n\nThe **AWS X-Ray Propagator** provides a propagator that when used, adds a `trace\nheader`_ to outgoing traces that is compatible with the AWS X-Ray backend\nservice. This allows the trace context to be propagated when a trace spans\nmultiple AWS services.\n\nThe same propagator setup is used to extract a context sent by external systems\nso that child span have the correct parent context.\n\n**NOTE**: Because the parent context parsed from the ``X-Amzn-Trace-Id`` header\nassumes the context is _not_ sampled by default, users should make sure to add\n``Sampled=1`` to their ``X-Amzn-Trace-Id`` headers so that the child spans are\nsampled.\n\nUsage\n-----\n\nUse the provided AWS X-Ray Propagator to inject the necessary context into\ntraces sent to external systems.\n\nThis can be done by either setting this environment variable:\n\n::\n\n    export OTEL_PROPAGATORS = xray\n\n\nOr by setting this propagator in your instrumented application:\n\n.. code-block:: python\n\n    from opentelemetry.propagate import set_global_textmap\n    from opentelemetry.propagators.aws import AwsXRayPropagator\n\n    set_global_textmap(AwsXRayPropagator())\n\nAPI\n---\n.. _trace header: https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader\n\"\"\"\n\nimport logging\nimport typing\n\nfrom opentelemetry import trace\nfrom opentelemetry.context import Context\nfrom opentelemetry.propagators.textmap import (\n    CarrierT,\n    Getter,\n    Setter,\n    TextMapPropagator,\n    default_getter,\n    default_setter,\n)\n\nTRACE_HEADER_KEY = \"X-Amzn-Trace-Id\"\nKV_PAIR_DELIMITER = \";\"\nKEY_AND_VALUE_DELIMITER = \"=\"\n\nTRACE_ID_KEY = \"Root\"\nTRACE_ID_LENGTH = 35\nTRACE_ID_VERSION = \"1\"\nTRACE_ID_DELIMITER = \"-\"\nTRACE_ID_DELIMITER_INDEX_1 = 1\nTRACE_ID_DELIMITER_INDEX_2 = 10\nTRACE_ID_FIRST_PART_LENGTH = 8\n\nPARENT_ID_KEY = \"Parent\"\nPARENT_ID_LENGTH = 16\n\nSAMPLED_FLAG_KEY = \"Sampled\"\nSAMPLED_FLAG_LENGTH = 1\nIS_SAMPLED = \"1\"\nNOT_SAMPLED = \"0\"\n\n\n_logger = logging.getLogger(__name__)\n\n\nclass AwsParseTraceHeaderError(Exception):\n    def __init__(self, message):\n        super().__init__()\n        self.message = message\n\n\nclass AwsXRayPropagator(TextMapPropagator):\n    \"\"\"Propagator for the AWS X-Ray Trace Header propagation protocol.\n\n    See:\n    https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader\n    \"\"\"\n\n    # AWS\n\n    def extract(\n        self,\n        carrier: CarrierT,\n        context: typing.Optional[Context] = None,\n        getter: Getter[CarrierT] = default_getter,\n    ) -> Context:\n        if context is None:\n            context = Context()\n\n        trace_header_list = getter.get(carrier, TRACE_HEADER_KEY)\n\n        if not trace_header_list or len(trace_header_list) != 1:\n            return context\n\n        trace_header = trace_header_list[0]\n\n        if not trace_header:\n            return context\n\n        try:\n            (\n                trace_id,\n                span_id,\n                sampled,\n            ) = AwsXRayPropagator._extract_span_properties(trace_header)\n        except AwsParseTraceHeaderError as err:\n            _logger.debug(err.message)\n            return context\n\n        options = 0\n        if sampled:\n            options |= trace.TraceFlags.SAMPLED\n\n        span_context = trace.SpanContext(\n            trace_id=trace_id,\n            span_id=span_id,\n            is_remote=True,\n            trace_flags=trace.TraceFlags(options),\n            trace_state=trace.TraceState(),\n        )\n\n        if not span_context.is_valid:\n            _logger.debug(\n                \"Invalid Span Extracted. Inserting INVALID span into provided context.\"\n            )\n            return context\n\n        return trace.set_span_in_context(\n            trace.NonRecordingSpan(span_context), context=context\n        )\n\n    @staticmethod\n    def _extract_span_properties(trace_header):\n        trace_id = trace.INVALID_TRACE_ID\n        span_id = trace.INVALID_SPAN_ID\n        sampled = False\n\n        for kv_pair_str in trace_header.split(KV_PAIR_DELIMITER):\n            try:\n                key_str, value_str = kv_pair_str.split(KEY_AND_VALUE_DELIMITER)\n                key, value = key_str.strip(), value_str.strip()\n            except ValueError as ex:\n                raise AwsParseTraceHeaderError(\n                    (\n                        \"Error parsing X-Ray trace header. Invalid key value pair: %s. Returning INVALID span context.\",\n                        kv_pair_str,\n                    )\n                ) from ex\n            if key == TRACE_ID_KEY:\n                if not AwsXRayPropagator._validate_trace_id(value):\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    )\n\n                try:\n                    trace_id = AwsXRayPropagator._parse_trace_id(value)\n                except ValueError as ex:\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    ) from ex\n            elif key == PARENT_ID_KEY:\n                if not AwsXRayPropagator._validate_span_id(value):\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid ParentId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    )\n\n                try:\n                    span_id = AwsXRayPropagator._parse_span_id(value)\n                except ValueError as ex:\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    ) from ex\n            elif key == SAMPLED_FLAG_KEY:\n                if not AwsXRayPropagator._validate_sampled_flag(value):\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid Sampling flag in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    )\n\n                sampled = AwsXRayPropagator._parse_sampled_flag(value)\n\n        return trace_id, span_id, sampled\n\n    @staticmethod\n    def _validate_trace_id(trace_id_str):\n        return (\n            len(trace_id_str) == TRACE_ID_LENGTH\n            and trace_id_str.startswith(TRACE_ID_VERSION)\n            and trace_id_str[TRACE_ID_DELIMITER_INDEX_1] == TRACE_ID_DELIMITER\n            and trace_id_str[TRACE_ID_DELIMITER_INDEX_2] == TRACE_ID_DELIMITER\n        )\n\n    @staticmethod\n    def _parse_trace_id(trace_id_str):\n        timestamp_subset = trace_id_str[\n            TRACE_ID_DELIMITER_INDEX_1 + 1 : TRACE_ID_DELIMITER_INDEX_2\n        ]\n        unique_id_subset = trace_id_str[\n            TRACE_ID_DELIMITER_INDEX_2 + 1 : TRACE_ID_LENGTH\n        ]\n        return int(timestamp_subset + unique_id_subset, 16)\n\n    @staticmethod\n    def _validate_span_id(span_id_str):\n        return len(span_id_str) == PARENT_ID_LENGTH\n\n    @staticmethod\n    def _parse_span_id(span_id_str):\n        return int(span_id_str, 16)\n\n    @staticmethod\n    def _validate_sampled_flag(sampled_flag_str):\n        return len(\n            sampled_flag_str\n        ) == SAMPLED_FLAG_LENGTH and sampled_flag_str in (\n            IS_SAMPLED,\n            NOT_SAMPLED,\n        )\n\n    @staticmethod\n    def _parse_sampled_flag(sampled_flag_str):\n        return sampled_flag_str[0] == IS_SAMPLED\n\n    def inject(\n        self,\n        carrier: CarrierT,\n        context: typing.Optional[Context] = None,\n        setter: Setter[CarrierT] = default_setter,\n    ) -> None:\n        span = trace.get_current_span(context=context)\n\n        span_context = span.get_span_context()\n        if not span_context.is_valid:\n            return\n\n        otel_trace_id = f\"{span_context.trace_id:032x}\"\n        xray_trace_id = TRACE_ID_DELIMITER.join(\n            [\n                TRACE_ID_VERSION,\n                otel_trace_id[:TRACE_ID_FIRST_PART_LENGTH],\n                otel_trace_id[TRACE_ID_FIRST_PART_LENGTH:],\n            ]\n        )\n\n        parent_id = f\"{span_context.span_id:016x}\"\n\n        sampling_flag = (\n            IS_SAMPLED\n            if span_context.trace_flags & trace.TraceFlags.SAMPLED\n            else NOT_SAMPLED\n        )\n\n        # TODO: Add OT trace state to the X-Ray trace header\n\n        trace_header = KV_PAIR_DELIMITER.join(\n            [\n                KEY_AND_VALUE_DELIMITER.join([key, value])\n                for key, value in [\n                    (TRACE_ID_KEY, xray_trace_id),\n                    (PARENT_ID_KEY, parent_id),\n                    (SAMPLED_FLAG_KEY, sampling_flag),\n                ]\n            ]\n        )\n\n        setter.set(\n            carrier,\n            TRACE_HEADER_KEY,\n            trace_header,\n        )\n\n    @property\n    def fields(self):\n        \"\"\"Returns a set with the fields set in `inject`.\"\"\"\n\n        return {TRACE_HEADER_KEY}\n", "path": "propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nAWS X-Ray Propagator\n--------------------\n\nThe **AWS X-Ray Propagator** provides a propagator that when used, adds a `trace\nheader`_ to outgoing traces that is compatible with the AWS X-Ray backend\nservice. This allows the trace context to be propagated when a trace spans\nmultiple AWS services.\n\nThe same propagator setup is used to extract a context sent by external systems\nso that child span have the correct parent context.\n\n**NOTE**: Because the parent context parsed from the ``X-Amzn-Trace-Id`` header\nassumes the context is _not_ sampled by default, users should make sure to add\n``Sampled=1`` to their ``X-Amzn-Trace-Id`` headers so that the child spans are\nsampled.\n\nUsage\n-----\n\nUse the provided AWS X-Ray Propagator to inject the necessary context into\ntraces sent to external systems.\n\nThis can be done by either setting this environment variable:\n\n::\n\n    export OTEL_PROPAGATORS = xray\n\n\nOr by setting this propagator in your instrumented application:\n\n.. code-block:: python\n\n    from opentelemetry.propagate import set_global_textmap\n    from opentelemetry.propagators.aws import AwsXRayPropagator\n\n    set_global_textmap(AwsXRayPropagator())\n\nAPI\n---\n.. _trace header: https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader\n\"\"\"\n\nimport logging\nimport typing\nfrom os import environ\n\nfrom opentelemetry import trace\nfrom opentelemetry.context import Context\nfrom opentelemetry.propagators.textmap import (\n    CarrierT,\n    Getter,\n    Setter,\n    TextMapPropagator,\n    default_getter,\n    default_setter,\n)\n\nTRACE_HEADER_KEY = \"X-Amzn-Trace-Id\"\nAWS_TRACE_HEADER_ENV_KEY = \"_X_AMZN_TRACE_ID\"\nKV_PAIR_DELIMITER = \";\"\nKEY_AND_VALUE_DELIMITER = \"=\"\n\nTRACE_ID_KEY = \"Root\"\nTRACE_ID_LENGTH = 35\nTRACE_ID_VERSION = \"1\"\nTRACE_ID_DELIMITER = \"-\"\nTRACE_ID_DELIMITER_INDEX_1 = 1\nTRACE_ID_DELIMITER_INDEX_2 = 10\nTRACE_ID_FIRST_PART_LENGTH = 8\n\nPARENT_ID_KEY = \"Parent\"\nPARENT_ID_LENGTH = 16\n\nSAMPLED_FLAG_KEY = \"Sampled\"\nSAMPLED_FLAG_LENGTH = 1\nIS_SAMPLED = \"1\"\nNOT_SAMPLED = \"0\"\n\n\n_logger = logging.getLogger(__name__)\n\n\nclass AwsParseTraceHeaderError(Exception):\n    def __init__(self, message):\n        super().__init__()\n        self.message = message\n\n\nclass AwsXRayPropagator(TextMapPropagator):\n    \"\"\"Propagator for the AWS X-Ray Trace Header propagation protocol.\n\n    See:\n    https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader\n    \"\"\"\n\n    # AWS\n\n    def extract(\n        self,\n        carrier: CarrierT,\n        context: typing.Optional[Context] = None,\n        getter: Getter[CarrierT] = default_getter,\n    ) -> Context:\n        if context is None:\n            context = Context()\n\n        trace_header_list = getter.get(carrier, TRACE_HEADER_KEY)\n\n        if not trace_header_list or len(trace_header_list) != 1:\n            return context\n\n        trace_header = trace_header_list[0]\n\n        if not trace_header:\n            return context\n\n        try:\n            (\n                trace_id,\n                span_id,\n                sampled,\n            ) = AwsXRayPropagator._extract_span_properties(trace_header)\n        except AwsParseTraceHeaderError as err:\n            _logger.debug(err.message)\n            return context\n\n        options = 0\n        if sampled:\n            options |= trace.TraceFlags.SAMPLED\n\n        span_context = trace.SpanContext(\n            trace_id=trace_id,\n            span_id=span_id,\n            is_remote=True,\n            trace_flags=trace.TraceFlags(options),\n            trace_state=trace.TraceState(),\n        )\n\n        if not span_context.is_valid:\n            _logger.debug(\n                \"Invalid Span Extracted. Inserting INVALID span into provided context.\"\n            )\n            return context\n\n        return trace.set_span_in_context(\n            trace.NonRecordingSpan(span_context), context=context\n        )\n\n    @staticmethod\n    def _extract_span_properties(trace_header):\n        trace_id = trace.INVALID_TRACE_ID\n        span_id = trace.INVALID_SPAN_ID\n        sampled = False\n\n        for kv_pair_str in trace_header.split(KV_PAIR_DELIMITER):\n            try:\n                key_str, value_str = kv_pair_str.split(KEY_AND_VALUE_DELIMITER)\n                key, value = key_str.strip(), value_str.strip()\n            except ValueError as ex:\n                raise AwsParseTraceHeaderError(\n                    (\n                        \"Error parsing X-Ray trace header. Invalid key value pair: %s. Returning INVALID span context.\",\n                        kv_pair_str,\n                    )\n                ) from ex\n            if key == TRACE_ID_KEY:\n                if not AwsXRayPropagator._validate_trace_id(value):\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    )\n\n                try:\n                    trace_id = AwsXRayPropagator._parse_trace_id(value)\n                except ValueError as ex:\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    ) from ex\n            elif key == PARENT_ID_KEY:\n                if not AwsXRayPropagator._validate_span_id(value):\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid ParentId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    )\n\n                try:\n                    span_id = AwsXRayPropagator._parse_span_id(value)\n                except ValueError as ex:\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid TraceId in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    ) from ex\n            elif key == SAMPLED_FLAG_KEY:\n                if not AwsXRayPropagator._validate_sampled_flag(value):\n                    raise AwsParseTraceHeaderError(\n                        (\n                            \"Invalid Sampling flag in X-Ray trace header: '%s' with value '%s'. Returning INVALID span context.\",\n                            TRACE_HEADER_KEY,\n                            trace_header,\n                        )\n                    )\n\n                sampled = AwsXRayPropagator._parse_sampled_flag(value)\n\n        return trace_id, span_id, sampled\n\n    @staticmethod\n    def _validate_trace_id(trace_id_str):\n        return (\n            len(trace_id_str) == TRACE_ID_LENGTH\n            and trace_id_str.startswith(TRACE_ID_VERSION)\n            and trace_id_str[TRACE_ID_DELIMITER_INDEX_1] == TRACE_ID_DELIMITER\n            and trace_id_str[TRACE_ID_DELIMITER_INDEX_2] == TRACE_ID_DELIMITER\n        )\n\n    @staticmethod\n    def _parse_trace_id(trace_id_str):\n        timestamp_subset = trace_id_str[\n            TRACE_ID_DELIMITER_INDEX_1 + 1 : TRACE_ID_DELIMITER_INDEX_2\n        ]\n        unique_id_subset = trace_id_str[\n            TRACE_ID_DELIMITER_INDEX_2 + 1 : TRACE_ID_LENGTH\n        ]\n        return int(timestamp_subset + unique_id_subset, 16)\n\n    @staticmethod\n    def _validate_span_id(span_id_str):\n        return len(span_id_str) == PARENT_ID_LENGTH\n\n    @staticmethod\n    def _parse_span_id(span_id_str):\n        return int(span_id_str, 16)\n\n    @staticmethod\n    def _validate_sampled_flag(sampled_flag_str):\n        return len(\n            sampled_flag_str\n        ) == SAMPLED_FLAG_LENGTH and sampled_flag_str in (\n            IS_SAMPLED,\n            NOT_SAMPLED,\n        )\n\n    @staticmethod\n    def _parse_sampled_flag(sampled_flag_str):\n        return sampled_flag_str[0] == IS_SAMPLED\n\n    def inject(\n        self,\n        carrier: CarrierT,\n        context: typing.Optional[Context] = None,\n        setter: Setter[CarrierT] = default_setter,\n    ) -> None:\n        span = trace.get_current_span(context=context)\n\n        span_context = span.get_span_context()\n        if not span_context.is_valid:\n            return\n\n        otel_trace_id = f\"{span_context.trace_id:032x}\"\n        xray_trace_id = TRACE_ID_DELIMITER.join(\n            [\n                TRACE_ID_VERSION,\n                otel_trace_id[:TRACE_ID_FIRST_PART_LENGTH],\n                otel_trace_id[TRACE_ID_FIRST_PART_LENGTH:],\n            ]\n        )\n\n        parent_id = f\"{span_context.span_id:016x}\"\n\n        sampling_flag = (\n            IS_SAMPLED\n            if span_context.trace_flags & trace.TraceFlags.SAMPLED\n            else NOT_SAMPLED\n        )\n\n        # TODO: Add OT trace state to the X-Ray trace header\n\n        trace_header = KV_PAIR_DELIMITER.join(\n            [\n                KEY_AND_VALUE_DELIMITER.join([key, value])\n                for key, value in [\n                    (TRACE_ID_KEY, xray_trace_id),\n                    (PARENT_ID_KEY, parent_id),\n                    (SAMPLED_FLAG_KEY, sampling_flag),\n                ]\n            ]\n        )\n\n        setter.set(\n            carrier,\n            TRACE_HEADER_KEY,\n            trace_header,\n        )\n\n    @property\n    def fields(self):\n        \"\"\"Returns a set with the fields set in `inject`.\"\"\"\n\n        return {TRACE_HEADER_KEY}\n\n\nclass AwsXrayLambdaPropagator(AwsXRayPropagator):\n    \"\"\"Implementation of the AWS X-Ray Trace Header propagation protocol but\n    with special handling for Lambda's ``_X_AMZN_TRACE_ID` environment\n    variable.\n    \"\"\"\n\n    def extract(\n        self,\n        carrier: CarrierT,\n        context: typing.Optional[Context] = None,\n        getter: Getter[CarrierT] = default_getter,\n    ) -> Context:\n\n        xray_context = super().extract(carrier, context=context, getter=getter)\n\n        if trace.get_current_span(context=context).get_span_context().is_valid:\n            return xray_context\n\n        trace_header = environ.get(AWS_TRACE_HEADER_ENV_KEY)\n\n        if trace_header is None:\n            return xray_context\n\n        return super().extract(\n            {TRACE_HEADER_KEY: trace_header},\n            context=xray_context,\n            getter=getter,\n        )\n", "path": "propagator/opentelemetry-propagator-aws-xray/src/opentelemetry/propagators/aws/aws_xray_propagator.py"}]}