We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Providing Parent in X-Amzn-Trace-Id results in no spans being exported
There's a good chance this is user error. If so, I'd appreciate a pointer to the relevant doc.

**Describe your environment** 
- Python 3.9
- fastapi==0.65.3
- opentelemetry-api==1.4.1
- opentelemetry-exporter-otlp==1.4.1
- opentelemetry-exporter-otlp-proto-grpc==1.4.1
- opentelemetry-instrumentation==0.23b2
- opentelemetry-instrumentation-asgi==0.23b2
- opentelemetry-instrumentation-fastapi==0.23b2
- opentelemetry-proto==1.4.1
- opentelemetry-sdk==1.4.1
- opentelemetry-sdk-extension-aws==0.23b2
- opentelemetry-semantic-conventions==0.23b2
- opentelemetry-util-http==0.23b2

**Steps to reproduce**
Using this sample application:
```
import fastapi
import uvicorn
from opentelemetry import propagate, trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.sdk.extension.aws.trace import AwsXRayIdGenerator
from opentelemetry.sdk.extension.aws.trace.propagation.aws_xray_format import AwsXRayFormat
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

app = fastapi.FastAPI()

@app.get("/foo")
async def foo():
    return {"message": "foo"}


# Setup AWS X-Ray Propagator
propagate.set_global_textmap(AwsXRayFormat())

# Setup Tracer
otlp_exporter = OTLPSpanExporter()
span_processor = BatchSpanProcessor(otlp_exporter)

tracer_provider = TracerProvider(id_generator=AwsXRayIdGenerator())
tracer_provider.add_span_processor(span_processor)

trace.set_tracer_provider(tracer_provider)

FastAPIInstrumentor.instrument_app(app)

uvicorn.run(app)
```

Calling: `curl 'http://localhost:8000/foo'` produces a span that is exported by my collector to X-Ray.

Calling: `curl 'http://localhost:8000/foo' -H 'X-Amzn-Trace-Id: Root=1-612fa749-271fa48e4c544863a13425d5;Parent=86153bfee2237b3b'` does not export a span.

**What is the expected behavior?**
My frontend application is producing requests with `X-Amzn-Trace-Id` in the format above. The frontend is separately sending X-Ray data. I'm expecting the trace ID generated by the frontend to be the root of the of the server segment so I can correlate the frontend activity and the backend activity.

**What is the actual behavior?**
When providing the header from the frontend, no span is generated by the backend. The frontend succeeds in generating spans that I see in the X-Ray console. No backend segments are seen.

**Additional context**
Unsure if #445 is related. It's the only thing that I could find in the issues that might be.


--- END ISSUE ---

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

{"golden_diff": "diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/propagation/aws_xray_format.py b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/propagation/aws_xray_format.py\n--- a/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/propagation/aws_xray_format.py\n+++ b/sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/propagation/aws_xray_format.py\n@@ -18,9 +18,17 @@\n \n The **AWS X-Ray Propagator** provides a propagator that when used, adds a `trace\n header`_ to outgoing traces that is compatible with the AWS X-Ray backend service.\n-This allows the trace context to be propagated when a trace span multiple AWS\n+This allows the trace context to be propagated when a trace spans multiple AWS\n services.\n \n+The same propagator setup is used to extract a context sent by external systems\n+so that child span have the correct parent context.\n+\n+**NOTE**: Because the parent context parsed from the ``X-Amzn-Trace-Id`` header\n+assumes 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\n+sampled.\n+\n Usage\n -----\n", "issue": "Providing Parent in X-Amzn-Trace-Id results in no spans being exported\nThere's a good chance this is user error. If so, I'd appreciate a pointer to the relevant doc.\r\n\r\n**Describe your environment** \r\n- Python 3.9\r\n- fastapi==0.65.3\r\n- opentelemetry-api==1.4.1\r\n- opentelemetry-exporter-otlp==1.4.1\r\n- opentelemetry-exporter-otlp-proto-grpc==1.4.1\r\n- opentelemetry-instrumentation==0.23b2\r\n- opentelemetry-instrumentation-asgi==0.23b2\r\n- opentelemetry-instrumentation-fastapi==0.23b2\r\n- opentelemetry-proto==1.4.1\r\n- opentelemetry-sdk==1.4.1\r\n- opentelemetry-sdk-extension-aws==0.23b2\r\n- opentelemetry-semantic-conventions==0.23b2\r\n- opentelemetry-util-http==0.23b2\r\n\r\n**Steps to reproduce**\r\nUsing this sample application:\r\n```\r\nimport fastapi\r\nimport uvicorn\r\nfrom opentelemetry import propagate, trace\r\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\r\nfrom opentelemetry.instrumentation.fastapi import FastAPIInstrumentor\r\nfrom opentelemetry.sdk.extension.aws.trace import AwsXRayIdGenerator\r\nfrom opentelemetry.sdk.extension.aws.trace.propagation.aws_xray_format import AwsXRayFormat\r\nfrom opentelemetry.sdk.trace import TracerProvider\r\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\r\n\r\napp = fastapi.FastAPI()\r\n\r\n@app.get(\"/foo\")\r\nasync def foo():\r\n    return {\"message\": \"foo\"}\r\n\r\n\r\n# Setup AWS X-Ray Propagator\r\npropagate.set_global_textmap(AwsXRayFormat())\r\n\r\n# Setup Tracer\r\notlp_exporter = OTLPSpanExporter()\r\nspan_processor = BatchSpanProcessor(otlp_exporter)\r\n\r\ntracer_provider = TracerProvider(id_generator=AwsXRayIdGenerator())\r\ntracer_provider.add_span_processor(span_processor)\r\n\r\ntrace.set_tracer_provider(tracer_provider)\r\n\r\nFastAPIInstrumentor.instrument_app(app)\r\n\r\nuvicorn.run(app)\r\n```\r\n\r\nCalling: `curl 'http://localhost:8000/foo'` produces a span that is exported by my collector to X-Ray.\r\n\r\nCalling: `curl 'http://localhost:8000/foo' -H 'X-Amzn-Trace-Id: Root=1-612fa749-271fa48e4c544863a13425d5;Parent=86153bfee2237b3b'` does not export a span.\r\n\r\n**What is the expected behavior?**\r\nMy frontend application is producing requests with `X-Amzn-Trace-Id` in the format above. The frontend is separately sending X-Ray data. I'm expecting the trace ID generated by the frontend to be the root of the of the server segment so I can correlate the frontend activity and the backend activity.\r\n\r\n**What is the actual behavior?**\r\nWhen providing the header from the frontend, no span is generated by the backend. The frontend succeeds in generating spans that I see in the X-Ray console. No backend segments are seen.\r\n\r\n**Additional context**\r\nUnsure if #445 is related. It's the only thing that I could find in the issues that might be.\r\n\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 service.\nThis allows the trace context to be propagated when a trace span multiple AWS\nservices.\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.sdk.extension.aws.trace.propagation.aws_xray_format import AwsXRayFormat\n\n    set_global_textmap(AwsXRayFormat())\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 AwsXRayFormat(TextMapPropagator):\n    \"\"\"Propagator for the AWS X-Ray Trace Header propagation protocol.\n\n    See: 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 = 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            ) = AwsXRayFormat._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. Insertting 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 AwsXRayFormat._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 = AwsXRayFormat._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 AwsXRayFormat._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 = AwsXRayFormat._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 AwsXRayFormat._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 = AwsXRayFormat._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 = 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 = \"{:032x}\".format(span_context.trace_id)\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 = \"{:016x}\".format(span_context.span_id)\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, TRACE_HEADER_KEY, 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": "sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/propagation/aws_xray_format.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 service.\nThis allows the trace context to be propagated when a trace spans multiple AWS\nservices.\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.sdk.extension.aws.trace.propagation.aws_xray_format import AwsXRayFormat\n\n    set_global_textmap(AwsXRayFormat())\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 AwsXRayFormat(TextMapPropagator):\n    \"\"\"Propagator for the AWS X-Ray Trace Header propagation protocol.\n\n    See: 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 = 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            ) = AwsXRayFormat._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. Insertting 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 AwsXRayFormat._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 = AwsXRayFormat._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 AwsXRayFormat._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 = AwsXRayFormat._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 AwsXRayFormat._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 = AwsXRayFormat._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 = 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 = \"{:032x}\".format(span_context.trace_id)\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 = \"{:016x}\".format(span_context.span_id)\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, TRACE_HEADER_KEY, 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": "sdk-extension/opentelemetry-sdk-extension-aws/src/opentelemetry/sdk/extension/aws/trace/propagation/aws_xray_format.py"}]}