We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ParentBased sampler ignores sample decision of parent when creating span via implicit Context
When having a `ParentBased` sampler setup and creating a span via `tracer.start_span` without explicitly providing a `context` as parent, possible parent spans in the current `Context` are ignored [ignored](https://github.com/open-telemetry/opentelemetry-python/blob/v0.15b0/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py#L230). 
Since for implicit parents the passed `context` is always `None` the `ParentBased` sampler needs to consider also parent Spans in the current `Context` and, if available, respect their sampling flag instead of forwarding to the delegate sampler.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.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 For general information about sampling, see `the specification <https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#sampling>`_.
17 
18 OpenTelemetry provides two types of samplers:
19 
20 - `StaticSampler`
21 - `TraceIdRatioBased`
22 
23 A `StaticSampler` always returns the same sampling result regardless of the conditions. Both possible StaticSamplers are already created:
24 
25 - Always sample spans: ALWAYS_ON
26 - Never sample spans: ALWAYS_OFF
27 
28 A `TraceIdRatioBased` sampler makes a random sampling result based on the sampling probability given.
29 
30 If the span being sampled has a parent, `ParentBased` will respect the parent span's sampling result. Otherwise, it returns the sampling result from the given delegate sampler.
31 
32 Currently, sampling results are always made during the creation of the span. However, this might not always be the case in the future (see `OTEP #115 <https://github.com/open-telemetry/oteps/pull/115>`_).
33 
34 Custom samplers can be created by subclassing `Sampler` and implementing `Sampler.should_sample` as well as `Sampler.get_description`.
35 
36 To use a sampler, pass it into the tracer provider constructor. For example:
37 
38 .. code:: python
39 
40     from opentelemetry import trace
41     from opentelemetry.sdk.trace import TracerProvider
42     from opentelemetry.sdk.trace.export import (
43         ConsoleSpanExporter,
44         SimpleExportSpanProcessor,
45     )
46     from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
47 
48     # sample 1 in every 1000 traces
49     sampler = TraceIdRatioBased(1/1000)
50 
51     # set the sampler onto the global tracer provider
52     trace.set_tracer_provider(TracerProvider(sampler=sampler))
53 
54     # set up an exporter for sampled spans
55     trace.get_tracer_provider().add_span_processor(
56         SimpleExportSpanProcessor(ConsoleSpanExporter())
57     )
58 
59     # created spans will now be sampled by the TraceIdRatioBased sampler
60     with trace.get_tracer(__name__).start_as_current_span("Test Span"):
61         ...
62 """
63 import abc
64 import enum
65 from types import MappingProxyType
66 from typing import Optional, Sequence
67 
68 # pylint: disable=unused-import
69 from opentelemetry.context import Context
70 from opentelemetry.trace import Link, get_current_span
71 from opentelemetry.trace.span import TraceState
72 from opentelemetry.util.types import Attributes
73 
74 
75 class Decision(enum.Enum):
76     # IsRecording() == false, span will not be recorded and all events and attributes will be dropped.
77     DROP = 0
78     # IsRecording() == true, but Sampled flag MUST NOT be set.
79     RECORD_ONLY = 1
80     # IsRecording() == true AND Sampled flag` MUST be set.
81     RECORD_AND_SAMPLE = 2
82 
83     def is_recording(self):
84         return self in (Decision.RECORD_ONLY, Decision.RECORD_AND_SAMPLE)
85 
86     def is_sampled(self):
87         return self is Decision.RECORD_AND_SAMPLE
88 
89 
90 class SamplingResult:
91     """A sampling result as applied to a newly-created Span.
92 
93     Args:
94         decision: A sampling decision based off of whether the span is recorded
95             and the sampled flag in trace flags in the span context.
96         attributes: Attributes to add to the `opentelemetry.trace.Span`.
97         trace_state: The tracestate used for the `opentelemetry.trace.Span`.
98             Could possibly have been modified by the sampler.
99     """
100 
101     def __repr__(self) -> str:
102         return "{}({}, attributes={})".format(
103             type(self).__name__, str(self.decision), str(self.attributes)
104         )
105 
106     def __init__(
107         self,
108         decision: Decision,
109         attributes: "Attributes" = None,
110         trace_state: "TraceState" = None,
111     ) -> None:
112         self.decision = decision
113         if attributes is None:
114             self.attributes = MappingProxyType({})
115         else:
116             self.attributes = MappingProxyType(attributes)
117         self.trace_state = trace_state
118 
119 
120 class Sampler(abc.ABC):
121     @abc.abstractmethod
122     def should_sample(
123         self,
124         parent_context: Optional["Context"],
125         trace_id: int,
126         name: str,
127         attributes: Attributes = None,
128         links: Sequence["Link"] = None,
129         trace_state: "TraceState" = None,
130     ) -> "SamplingResult":
131         pass
132 
133     @abc.abstractmethod
134     def get_description(self) -> str:
135         pass
136 
137 
138 class StaticSampler(Sampler):
139     """Sampler that always returns the same decision."""
140 
141     def __init__(self, decision: "Decision"):
142         self._decision = decision
143 
144     def should_sample(
145         self,
146         parent_context: Optional["Context"],
147         trace_id: int,
148         name: str,
149         attributes: Attributes = None,
150         links: Sequence["Link"] = None,
151         trace_state: "TraceState" = None,
152     ) -> "SamplingResult":
153         if self._decision is Decision.DROP:
154             return SamplingResult(self._decision)
155         return SamplingResult(self._decision, attributes, trace_state)
156 
157     def get_description(self) -> str:
158         if self._decision is Decision.DROP:
159             return "AlwaysOffSampler"
160         return "AlwaysOnSampler"
161 
162 
163 class TraceIdRatioBased(Sampler):
164     """
165     Sampler that makes sampling decisions probabalistically based on `rate`,
166     while also respecting the parent span sampling decision.
167 
168     Args:
169         rate: Probability (between 0 and 1) that a span will be sampled
170     """
171 
172     def __init__(self, rate: float):
173         if rate < 0.0 or rate > 1.0:
174             raise ValueError("Probability must be in range [0.0, 1.0].")
175         self._rate = rate
176         self._bound = self.get_bound_for_rate(self._rate)
177 
178     # For compatibility with 64 bit trace IDs, the sampler checks the 64
179     # low-order bits of the trace ID to decide whether to sample a given trace.
180     TRACE_ID_LIMIT = (1 << 64) - 1
181 
182     @classmethod
183     def get_bound_for_rate(cls, rate: float) -> int:
184         return round(rate * (cls.TRACE_ID_LIMIT + 1))
185 
186     @property
187     def rate(self) -> float:
188         return self._rate
189 
190     @rate.setter
191     def rate(self, new_rate: float) -> None:
192         self._rate = new_rate
193         self._bound = self.get_bound_for_rate(self._rate)
194 
195     @property
196     def bound(self) -> int:
197         return self._bound
198 
199     def should_sample(
200         self,
201         parent_context: Optional["Context"],
202         trace_id: int,
203         name: str,
204         attributes: Attributes = None,
205         links: Sequence["Link"] = None,
206         trace_state: "TraceState" = None,
207     ) -> "SamplingResult":
208         decision = Decision.DROP
209         if trace_id & self.TRACE_ID_LIMIT < self.bound:
210             decision = Decision.RECORD_AND_SAMPLE
211         if decision is Decision.DROP:
212             return SamplingResult(decision)
213         return SamplingResult(decision, attributes)
214 
215     def get_description(self) -> str:
216         return "TraceIdRatioBased{{{}}}".format(self._rate)
217 
218 
219 class ParentBased(Sampler):
220     """
221     If a parent is set, follows the same sampling decision as the parent.
222     Otherwise, uses the delegate provided at initialization to make a
223     decision.
224 
225     Args:
226         delegate: The delegate sampler to use if parent is not set.
227     """
228 
229     def __init__(self, delegate: Sampler):
230         self._delegate = delegate
231 
232     def should_sample(
233         self,
234         parent_context: Optional["Context"],
235         trace_id: int,
236         name: str,
237         attributes: Attributes = None,
238         links: Sequence["Link"] = None,
239         trace_state: "TraceState" = None,
240     ) -> "SamplingResult":
241         if parent_context is not None:
242             parent_span_context = get_current_span(
243                 parent_context
244             ).get_span_context()
245             # only drop if parent exists and is not a root span
246             if (
247                 parent_span_context is not None
248                 and parent_span_context.is_valid
249                 and not parent_span_context.trace_flags.sampled
250             ):
251                 return SamplingResult(Decision.DROP)
252             return SamplingResult(Decision.RECORD_AND_SAMPLE, attributes)
253 
254         return self._delegate.should_sample(
255             parent_context=parent_context,
256             trace_id=trace_id,
257             name=name,
258             attributes=attributes,
259             links=links,
260             trace_state=trace_state,
261         )
262 
263     def get_description(self):
264         return "ParentBased{{{}}}".format(self._delegate.get_description())
265 
266 
267 ALWAYS_OFF = StaticSampler(Decision.DROP)
268 """Sampler that never samples spans, regardless of the parent span's sampling decision."""
269 
270 ALWAYS_ON = StaticSampler(Decision.RECORD_AND_SAMPLE)
271 """Sampler that always samples spans, regardless of the parent span's sampling decision."""
272 
273 DEFAULT_OFF = ParentBased(ALWAYS_OFF)
274 """Sampler that respects its parent span's sampling decision, but otherwise never samples."""
275 
276 DEFAULT_ON = ParentBased(ALWAYS_ON)
277 """Sampler that respects its parent span's sampling decision, but otherwise always samples."""
278
```
--- 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/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py
@@ -151,7 +151,7 @@
         trace_state: "TraceState" = None,
     ) -> "SamplingResult":
         if self._decision is Decision.DROP:
-            return SamplingResult(self._decision)
+            attributes = None
         return SamplingResult(self._decision, attributes, trace_state)
 
     def get_description(self) -> str:
@@ -209,8 +209,8 @@
         if trace_id & self.TRACE_ID_LIMIT < self.bound:
             decision = Decision.RECORD_AND_SAMPLE
         if decision is Decision.DROP:
-            return SamplingResult(decision)
-        return SamplingResult(decision, attributes)
+            attributes = None
+        return SamplingResult(decision, attributes, trace_state)
 
     def get_description(self) -> str:
         return "TraceIdRatioBased{{{}}}".format(self._rate)
@@ -238,18 +238,16 @@
         links: Sequence["Link"] = None,
         trace_state: "TraceState" = None,
     ) -> "SamplingResult":
-        if parent_context is not None:
-            parent_span_context = get_current_span(
-                parent_context
-            ).get_span_context()
-            # only drop if parent exists and is not a root span
-            if (
-                parent_span_context is not None
-                and parent_span_context.is_valid
-                and not parent_span_context.trace_flags.sampled
-            ):
-                return SamplingResult(Decision.DROP)
-            return SamplingResult(Decision.RECORD_AND_SAMPLE, attributes)
+        parent_span_context = get_current_span(
+            parent_context
+        ).get_span_context()
+        # respect the sampling flag of the parent if present
+        if parent_span_context is not None and parent_span_context.is_valid:
+            decision = Decision.RECORD_AND_SAMPLE
+            if not parent_span_context.trace_flags.sampled:
+                decision = Decision.DROP
+                attributes = None
+            return SamplingResult(decision, attributes, trace_state)
 
         return self._delegate.should_sample(
             parent_context=parent_context,

{"golden_diff": "diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py\n--- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py\n+++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py\n@@ -151,7 +151,7 @@\n         trace_state: \"TraceState\" = None,\n     ) -> \"SamplingResult\":\n         if self._decision is Decision.DROP:\n-            return SamplingResult(self._decision)\n+            attributes = None\n         return SamplingResult(self._decision, attributes, trace_state)\n \n     def get_description(self) -> str:\n@@ -209,8 +209,8 @@\n         if trace_id & self.TRACE_ID_LIMIT < self.bound:\n             decision = Decision.RECORD_AND_SAMPLE\n         if decision is Decision.DROP:\n-            return SamplingResult(decision)\n-        return SamplingResult(decision, attributes)\n+            attributes = None\n+        return SamplingResult(decision, attributes, trace_state)\n \n     def get_description(self) -> str:\n         return \"TraceIdRatioBased{{{}}}\".format(self._rate)\n@@ -238,18 +238,16 @@\n         links: Sequence[\"Link\"] = None,\n         trace_state: \"TraceState\" = None,\n     ) -> \"SamplingResult\":\n-        if parent_context is not None:\n-            parent_span_context = get_current_span(\n-                parent_context\n-            ).get_span_context()\n-            # only drop if parent exists and is not a root span\n-            if (\n-                parent_span_context is not None\n-                and parent_span_context.is_valid\n-                and not parent_span_context.trace_flags.sampled\n-            ):\n-                return SamplingResult(Decision.DROP)\n-            return SamplingResult(Decision.RECORD_AND_SAMPLE, attributes)\n+        parent_span_context = get_current_span(\n+            parent_context\n+        ).get_span_context()\n+        # respect the sampling flag of the parent if present\n+        if parent_span_context is not None and parent_span_context.is_valid:\n+            decision = Decision.RECORD_AND_SAMPLE\n+            if not parent_span_context.trace_flags.sampled:\n+                decision = Decision.DROP\n+                attributes = None\n+            return SamplingResult(decision, attributes, trace_state)\n \n         return self._delegate.should_sample(\n             parent_context=parent_context,\n", "issue": "ParentBased sampler ignores sample decision of parent when creating span via implicit Context\nWhen having a `ParentBased` sampler setup and creating a span via `tracer.start_span` without explicitly providing a `context` as parent, possible parent spans in the current `Context` are ignored [ignored](https://github.com/open-telemetry/opentelemetry-python/blob/v0.15b0/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py#L230). \r\nSince for implicit parents the passed `context` is always `None` the `ParentBased` sampler needs to consider also parent Spans in the current `Context` and, if available, respect their sampling flag instead of forwarding to the delegate sampler.\r\n\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\"\"\"\nFor general information about sampling, see `the specification <https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#sampling>`_.\n\nOpenTelemetry provides two types of samplers:\n\n- `StaticSampler`\n- `TraceIdRatioBased`\n\nA `StaticSampler` always returns the same sampling result regardless of the conditions. Both possible StaticSamplers are already created:\n\n- Always sample spans: ALWAYS_ON\n- Never sample spans: ALWAYS_OFF\n\nA `TraceIdRatioBased` sampler makes a random sampling result based on the sampling probability given.\n\nIf the span being sampled has a parent, `ParentBased` will respect the parent span's sampling result. Otherwise, it returns the sampling result from the given delegate sampler.\n\nCurrently, sampling results are always made during the creation of the span. However, this might not always be the case in the future (see `OTEP #115 <https://github.com/open-telemetry/oteps/pull/115>`_).\n\nCustom samplers can be created by subclassing `Sampler` and implementing `Sampler.should_sample` as well as `Sampler.get_description`.\n\nTo use a sampler, pass it into the tracer provider constructor. For example:\n\n.. code:: python\n\n    from opentelemetry import trace\n    from opentelemetry.sdk.trace import TracerProvider\n    from opentelemetry.sdk.trace.export import (\n        ConsoleSpanExporter,\n        SimpleExportSpanProcessor,\n    )\n    from opentelemetry.sdk.trace.sampling import TraceIdRatioBased\n\n    # sample 1 in every 1000 traces\n    sampler = TraceIdRatioBased(1/1000)\n\n    # set the sampler onto the global tracer provider\n    trace.set_tracer_provider(TracerProvider(sampler=sampler))\n\n    # set up an exporter for sampled spans\n    trace.get_tracer_provider().add_span_processor(\n        SimpleExportSpanProcessor(ConsoleSpanExporter())\n    )\n\n    # created spans will now be sampled by the TraceIdRatioBased sampler\n    with trace.get_tracer(__name__).start_as_current_span(\"Test Span\"):\n        ...\n\"\"\"\nimport abc\nimport enum\nfrom types import MappingProxyType\nfrom typing import Optional, Sequence\n\n# pylint: disable=unused-import\nfrom opentelemetry.context import Context\nfrom opentelemetry.trace import Link, get_current_span\nfrom opentelemetry.trace.span import TraceState\nfrom opentelemetry.util.types import Attributes\n\n\nclass Decision(enum.Enum):\n    # IsRecording() == false, span will not be recorded and all events and attributes will be dropped.\n    DROP = 0\n    # IsRecording() == true, but Sampled flag MUST NOT be set.\n    RECORD_ONLY = 1\n    # IsRecording() == true AND Sampled flag` MUST be set.\n    RECORD_AND_SAMPLE = 2\n\n    def is_recording(self):\n        return self in (Decision.RECORD_ONLY, Decision.RECORD_AND_SAMPLE)\n\n    def is_sampled(self):\n        return self is Decision.RECORD_AND_SAMPLE\n\n\nclass SamplingResult:\n    \"\"\"A sampling result as applied to a newly-created Span.\n\n    Args:\n        decision: A sampling decision based off of whether the span is recorded\n            and the sampled flag in trace flags in the span context.\n        attributes: Attributes to add to the `opentelemetry.trace.Span`.\n        trace_state: The tracestate used for the `opentelemetry.trace.Span`.\n            Could possibly have been modified by the sampler.\n    \"\"\"\n\n    def __repr__(self) -> str:\n        return \"{}({}, attributes={})\".format(\n            type(self).__name__, str(self.decision), str(self.attributes)\n        )\n\n    def __init__(\n        self,\n        decision: Decision,\n        attributes: \"Attributes\" = None,\n        trace_state: \"TraceState\" = None,\n    ) -> None:\n        self.decision = decision\n        if attributes is None:\n            self.attributes = MappingProxyType({})\n        else:\n            self.attributes = MappingProxyType(attributes)\n        self.trace_state = trace_state\n\n\nclass Sampler(abc.ABC):\n    @abc.abstractmethod\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        pass\n\n    @abc.abstractmethod\n    def get_description(self) -> str:\n        pass\n\n\nclass StaticSampler(Sampler):\n    \"\"\"Sampler that always returns the same decision.\"\"\"\n\n    def __init__(self, decision: \"Decision\"):\n        self._decision = decision\n\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        if self._decision is Decision.DROP:\n            return SamplingResult(self._decision)\n        return SamplingResult(self._decision, attributes, trace_state)\n\n    def get_description(self) -> str:\n        if self._decision is Decision.DROP:\n            return \"AlwaysOffSampler\"\n        return \"AlwaysOnSampler\"\n\n\nclass TraceIdRatioBased(Sampler):\n    \"\"\"\n    Sampler that makes sampling decisions probabalistically based on `rate`,\n    while also respecting the parent span sampling decision.\n\n    Args:\n        rate: Probability (between 0 and 1) that a span will be sampled\n    \"\"\"\n\n    def __init__(self, rate: float):\n        if rate < 0.0 or rate > 1.0:\n            raise ValueError(\"Probability must be in range [0.0, 1.0].\")\n        self._rate = rate\n        self._bound = self.get_bound_for_rate(self._rate)\n\n    # For compatibility with 64 bit trace IDs, the sampler checks the 64\n    # low-order bits of the trace ID to decide whether to sample a given trace.\n    TRACE_ID_LIMIT = (1 << 64) - 1\n\n    @classmethod\n    def get_bound_for_rate(cls, rate: float) -> int:\n        return round(rate * (cls.TRACE_ID_LIMIT + 1))\n\n    @property\n    def rate(self) -> float:\n        return self._rate\n\n    @rate.setter\n    def rate(self, new_rate: float) -> None:\n        self._rate = new_rate\n        self._bound = self.get_bound_for_rate(self._rate)\n\n    @property\n    def bound(self) -> int:\n        return self._bound\n\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        decision = Decision.DROP\n        if trace_id & self.TRACE_ID_LIMIT < self.bound:\n            decision = Decision.RECORD_AND_SAMPLE\n        if decision is Decision.DROP:\n            return SamplingResult(decision)\n        return SamplingResult(decision, attributes)\n\n    def get_description(self) -> str:\n        return \"TraceIdRatioBased{{{}}}\".format(self._rate)\n\n\nclass ParentBased(Sampler):\n    \"\"\"\n    If a parent is set, follows the same sampling decision as the parent.\n    Otherwise, uses the delegate provided at initialization to make a\n    decision.\n\n    Args:\n        delegate: The delegate sampler to use if parent is not set.\n    \"\"\"\n\n    def __init__(self, delegate: Sampler):\n        self._delegate = delegate\n\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        if parent_context is not None:\n            parent_span_context = get_current_span(\n                parent_context\n            ).get_span_context()\n            # only drop if parent exists and is not a root span\n            if (\n                parent_span_context is not None\n                and parent_span_context.is_valid\n                and not parent_span_context.trace_flags.sampled\n            ):\n                return SamplingResult(Decision.DROP)\n            return SamplingResult(Decision.RECORD_AND_SAMPLE, attributes)\n\n        return self._delegate.should_sample(\n            parent_context=parent_context,\n            trace_id=trace_id,\n            name=name,\n            attributes=attributes,\n            links=links,\n            trace_state=trace_state,\n        )\n\n    def get_description(self):\n        return \"ParentBased{{{}}}\".format(self._delegate.get_description())\n\n\nALWAYS_OFF = StaticSampler(Decision.DROP)\n\"\"\"Sampler that never samples spans, regardless of the parent span's sampling decision.\"\"\"\n\nALWAYS_ON = StaticSampler(Decision.RECORD_AND_SAMPLE)\n\"\"\"Sampler that always samples spans, regardless of the parent span's sampling decision.\"\"\"\n\nDEFAULT_OFF = ParentBased(ALWAYS_OFF)\n\"\"\"Sampler that respects its parent span's sampling decision, but otherwise never samples.\"\"\"\n\nDEFAULT_ON = ParentBased(ALWAYS_ON)\n\"\"\"Sampler that respects its parent span's sampling decision, but otherwise always samples.\"\"\"\n", "path": "opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.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\"\"\"\nFor general information about sampling, see `the specification <https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#sampling>`_.\n\nOpenTelemetry provides two types of samplers:\n\n- `StaticSampler`\n- `TraceIdRatioBased`\n\nA `StaticSampler` always returns the same sampling result regardless of the conditions. Both possible StaticSamplers are already created:\n\n- Always sample spans: ALWAYS_ON\n- Never sample spans: ALWAYS_OFF\n\nA `TraceIdRatioBased` sampler makes a random sampling result based on the sampling probability given.\n\nIf the span being sampled has a parent, `ParentBased` will respect the parent span's sampling result. Otherwise, it returns the sampling result from the given delegate sampler.\n\nCurrently, sampling results are always made during the creation of the span. However, this might not always be the case in the future (see `OTEP #115 <https://github.com/open-telemetry/oteps/pull/115>`_).\n\nCustom samplers can be created by subclassing `Sampler` and implementing `Sampler.should_sample` as well as `Sampler.get_description`.\n\nTo use a sampler, pass it into the tracer provider constructor. For example:\n\n.. code:: python\n\n    from opentelemetry import trace\n    from opentelemetry.sdk.trace import TracerProvider\n    from opentelemetry.sdk.trace.export import (\n        ConsoleSpanExporter,\n        SimpleExportSpanProcessor,\n    )\n    from opentelemetry.sdk.trace.sampling import TraceIdRatioBased\n\n    # sample 1 in every 1000 traces\n    sampler = TraceIdRatioBased(1/1000)\n\n    # set the sampler onto the global tracer provider\n    trace.set_tracer_provider(TracerProvider(sampler=sampler))\n\n    # set up an exporter for sampled spans\n    trace.get_tracer_provider().add_span_processor(\n        SimpleExportSpanProcessor(ConsoleSpanExporter())\n    )\n\n    # created spans will now be sampled by the TraceIdRatioBased sampler\n    with trace.get_tracer(__name__).start_as_current_span(\"Test Span\"):\n        ...\n\"\"\"\nimport abc\nimport enum\nfrom types import MappingProxyType\nfrom typing import Optional, Sequence\n\n# pylint: disable=unused-import\nfrom opentelemetry.context import Context\nfrom opentelemetry.trace import Link, get_current_span\nfrom opentelemetry.trace.span import TraceState\nfrom opentelemetry.util.types import Attributes\n\n\nclass Decision(enum.Enum):\n    # IsRecording() == false, span will not be recorded and all events and attributes will be dropped.\n    DROP = 0\n    # IsRecording() == true, but Sampled flag MUST NOT be set.\n    RECORD_ONLY = 1\n    # IsRecording() == true AND Sampled flag` MUST be set.\n    RECORD_AND_SAMPLE = 2\n\n    def is_recording(self):\n        return self in (Decision.RECORD_ONLY, Decision.RECORD_AND_SAMPLE)\n\n    def is_sampled(self):\n        return self is Decision.RECORD_AND_SAMPLE\n\n\nclass SamplingResult:\n    \"\"\"A sampling result as applied to a newly-created Span.\n\n    Args:\n        decision: A sampling decision based off of whether the span is recorded\n            and the sampled flag in trace flags in the span context.\n        attributes: Attributes to add to the `opentelemetry.trace.Span`.\n        trace_state: The tracestate used for the `opentelemetry.trace.Span`.\n            Could possibly have been modified by the sampler.\n    \"\"\"\n\n    def __repr__(self) -> str:\n        return \"{}({}, attributes={})\".format(\n            type(self).__name__, str(self.decision), str(self.attributes)\n        )\n\n    def __init__(\n        self,\n        decision: Decision,\n        attributes: \"Attributes\" = None,\n        trace_state: \"TraceState\" = None,\n    ) -> None:\n        self.decision = decision\n        if attributes is None:\n            self.attributes = MappingProxyType({})\n        else:\n            self.attributes = MappingProxyType(attributes)\n        self.trace_state = trace_state\n\n\nclass Sampler(abc.ABC):\n    @abc.abstractmethod\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        pass\n\n    @abc.abstractmethod\n    def get_description(self) -> str:\n        pass\n\n\nclass StaticSampler(Sampler):\n    \"\"\"Sampler that always returns the same decision.\"\"\"\n\n    def __init__(self, decision: \"Decision\"):\n        self._decision = decision\n\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        if self._decision is Decision.DROP:\n            attributes = None\n        return SamplingResult(self._decision, attributes, trace_state)\n\n    def get_description(self) -> str:\n        if self._decision is Decision.DROP:\n            return \"AlwaysOffSampler\"\n        return \"AlwaysOnSampler\"\n\n\nclass TraceIdRatioBased(Sampler):\n    \"\"\"\n    Sampler that makes sampling decisions probabalistically based on `rate`,\n    while also respecting the parent span sampling decision.\n\n    Args:\n        rate: Probability (between 0 and 1) that a span will be sampled\n    \"\"\"\n\n    def __init__(self, rate: float):\n        if rate < 0.0 or rate > 1.0:\n            raise ValueError(\"Probability must be in range [0.0, 1.0].\")\n        self._rate = rate\n        self._bound = self.get_bound_for_rate(self._rate)\n\n    # For compatibility with 64 bit trace IDs, the sampler checks the 64\n    # low-order bits of the trace ID to decide whether to sample a given trace.\n    TRACE_ID_LIMIT = (1 << 64) - 1\n\n    @classmethod\n    def get_bound_for_rate(cls, rate: float) -> int:\n        return round(rate * (cls.TRACE_ID_LIMIT + 1))\n\n    @property\n    def rate(self) -> float:\n        return self._rate\n\n    @rate.setter\n    def rate(self, new_rate: float) -> None:\n        self._rate = new_rate\n        self._bound = self.get_bound_for_rate(self._rate)\n\n    @property\n    def bound(self) -> int:\n        return self._bound\n\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        decision = Decision.DROP\n        if trace_id & self.TRACE_ID_LIMIT < self.bound:\n            decision = Decision.RECORD_AND_SAMPLE\n        if decision is Decision.DROP:\n            attributes = None\n        return SamplingResult(decision, attributes, trace_state)\n\n    def get_description(self) -> str:\n        return \"TraceIdRatioBased{{{}}}\".format(self._rate)\n\n\nclass ParentBased(Sampler):\n    \"\"\"\n    If a parent is set, follows the same sampling decision as the parent.\n    Otherwise, uses the delegate provided at initialization to make a\n    decision.\n\n    Args:\n        delegate: The delegate sampler to use if parent is not set.\n    \"\"\"\n\n    def __init__(self, delegate: Sampler):\n        self._delegate = delegate\n\n    def should_sample(\n        self,\n        parent_context: Optional[\"Context\"],\n        trace_id: int,\n        name: str,\n        attributes: Attributes = None,\n        links: Sequence[\"Link\"] = None,\n        trace_state: \"TraceState\" = None,\n    ) -> \"SamplingResult\":\n        parent_span_context = get_current_span(\n            parent_context\n        ).get_span_context()\n        # respect the sampling flag of the parent if present\n        if parent_span_context is not None and parent_span_context.is_valid:\n            decision = Decision.RECORD_AND_SAMPLE\n            if not parent_span_context.trace_flags.sampled:\n                decision = Decision.DROP\n                attributes = None\n            return SamplingResult(decision, attributes, trace_state)\n\n        return self._delegate.should_sample(\n            parent_context=parent_context,\n            trace_id=trace_id,\n            name=name,\n            attributes=attributes,\n            links=links,\n            trace_state=trace_state,\n        )\n\n    def get_description(self):\n        return \"ParentBased{{{}}}\".format(self._delegate.get_description())\n\n\nALWAYS_OFF = StaticSampler(Decision.DROP)\n\"\"\"Sampler that never samples spans, regardless of the parent span's sampling decision.\"\"\"\n\nALWAYS_ON = StaticSampler(Decision.RECORD_AND_SAMPLE)\n\"\"\"Sampler that always samples spans, regardless of the parent span's sampling decision.\"\"\"\n\nDEFAULT_OFF = ParentBased(ALWAYS_OFF)\n\"\"\"Sampler that respects its parent span's sampling decision, but otherwise never samples.\"\"\"\n\nDEFAULT_ON = ParentBased(ALWAYS_ON)\n\"\"\"Sampler that respects its parent span's sampling decision, but otherwise always samples.\"\"\"\n", "path": "opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py"}]}