def extract(cls, get_from_carrier, carrier): trace_id = format_trace_id(trace.INVALID_TRACE_ID) span_id = format_span_id(trace.INVALID_SPAN_ID) sampled = "0" flags = None single_header = _extract_first_element( get_from_carrier(carrier, cls.SINGLE_HEADER_KEY)) if single_header: # The b3 spec calls for the sampling state to be # "deferred", which is unspecified. This concept does not # translate to SpanContext, so we set it as recorded. sampled = "1" fields = single_header.split("-", 4) if len(fields) == 1: sampled = fields[0] elif len(fields) == 2: trace_id, span_id = fields elif len(fields) == 3: trace_id, span_id, sampled = fields elif len(fields) == 4: trace_id, span_id, sampled, _parent_span_id = fields else: return trace.INVALID_SPAN_CONTEXT else: trace_id = (_extract_first_element( get_from_carrier(carrier, cls.TRACE_ID_KEY)) or trace_id) span_id = (_extract_first_element( get_from_carrier(carrier, cls.SPAN_ID_KEY)) or span_id) sampled = (_extract_first_element( get_from_carrier(carrier, cls.SAMPLED_KEY)) or sampled) flags = (_extract_first_element( get_from_carrier(carrier, cls.FLAGS_KEY)) or flags) options = 0 # The b3 spec provides no defined behavior for both sample and # flag values set. Since the setting of at least one implies # the desire for some form of sampling, propagate if either # header is set to allow. if sampled in cls._SAMPLE_PROPAGATE_VALUES or flags == "1": options |= trace.TraceOptions.SAMPLED return trace.SpanContext( # trace an span ids are encoded in hex, so must be converted trace_id=int(trace_id, 16), span_id=int(span_id, 16), trace_options=trace.TraceOptions(options), trace_state=trace.TraceState(), )
def extract(cls, get_from_carrier: httptextformat.Getter[_T], carrier: _T) -> trace.SpanContext: """Extracts a valid SpanContext from the carrier. """ header = get_from_carrier(carrier, cls._TRACEPARENT_HEADER_NAME) if not header: return trace.INVALID_SPAN_CONTEXT match = re.search(cls._TRACEPARENT_HEADER_FORMAT_RE, header[0]) if not match: return trace.INVALID_SPAN_CONTEXT version = match.group(1) trace_id = match.group(2) span_id = match.group(3) trace_options = match.group(4) if trace_id == "0" * 32 or span_id == "0" * 16: return trace.INVALID_SPAN_CONTEXT if version == "00": if match.group(5): return trace.INVALID_SPAN_CONTEXT if version == "ff": return trace.INVALID_SPAN_CONTEXT tracestate_headers = get_from_carrier(carrier, cls._TRACESTATE_HEADER_NAME) tracestate = _parse_tracestate(tracestate_headers) span_context = trace.SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id, 16), trace_options=trace.TraceOptions(trace_options), trace_state=tracestate, ) return span_context
# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import unittest from opentelemetry import trace from opentelemetry.trace import sampling TO_DEFAULT = trace.TraceOptions(trace.TraceOptions.DEFAULT) TO_SAMPLED = trace.TraceOptions(trace.TraceOptions.SAMPLED) class TestSampler(unittest.TestCase): def test_always_on(self): no_record_always_on = sampling.ALWAYS_ON.should_sample( trace.SpanContext(0xDEADBEEF, 0xDEADBEF0, trace_options=TO_DEFAULT), 0xDEADBEF1, 0xDEADBEF2, "unsampled parent, sampling on", ) self.assertTrue(no_record_always_on.sampled) self.assertEqual(no_record_always_on.attributes, {})