def test_probability_sampler_limits(self): # Sample one of every 2^64 (= 5e-20) traces. This is the lowest # possible meaningful sampling rate, only traces with trace ID 0x0 # should get sampled. almost_always_off = sampling.TraceIdRatioBased(2**-64) self.assertTrue( almost_always_off.should_sample(None, 0x0, "span name").decision.is_sampled()) self.assertFalse( almost_always_off.should_sample(None, 0x1, "span name").decision.is_sampled()) self.assertEqual(sampling.TraceIdRatioBased.get_bound_for_rate(2**-64), 0x1) # Sample every trace with trace ID less than 0xffffffffffffffff. In # principle this is the highest possible sampling rate less than 1, but # we can't actually express this rate as a float! # # In practice, the highest possible sampling rate is: # # 1 - sys.float_info.epsilon almost_always_on = sampling.TraceIdRatioBased(1 - 2**-64) self.assertTrue( almost_always_on.should_sample(None, 0xFFFFFFFFFFFFFFFE, "span name").decision.is_sampled()) # These tests are logically consistent, but fail because of the float # precision issue above. Changing the sampler to check fewer bytes of # the trace ID will cause these to pass. # self.assertFalse( # almost_always_on.should_sample( # None, # 0xFFFFFFFFFFFFFFFF, # "span name", # ).decision.is_sampled() # ) # self.assertEqual( # sampling.TraceIdRatioBased.get_bound_for_rate(1 - 2 ** -64)), # 0xFFFFFFFFFFFFFFFF, # ) # Check that a sampler with the highest effective sampling rate < 1 # refuses to sample traces with trace ID 0xffffffffffffffff. almost_almost_always_on = sampling.TraceIdRatioBased( 1 - sys.float_info.epsilon) self.assertFalse( almost_almost_always_on.should_sample( None, 0xFFFFFFFFFFFFFFFF, "span name").decision.is_sampled()) # Check that the higest effective sampling rate is actually lower than # the highest theoretical sampling rate. If this test fails the test # above is wrong. self.assertLess( almost_almost_always_on.bound, 0xFFFFFFFFFFFFFFFF, )
def test_probability_sampler(self): sampler = sampling.TraceIdRatioBased(0.5) # Check that we sample based on the trace ID if the parent context is # null # trace_state should also be empty since it is based off of parent sampled_result = sampler.should_sample( None, 0x7FFFFFFFFFFFFFFF, "sampled true", trace.SpanKind.INTERNAL, attributes={"sampled.expect": "true"}, ) self.assertTrue(sampled_result.decision.is_sampled()) self.assertEqual(sampled_result.attributes, {"sampled.expect": "true"}) self.assertIsNone(sampled_result.trace_state) not_sampled_result = sampler.should_sample( None, 0x8000000000000000, "sampled false", trace.SpanKind.INTERNAL, attributes={"sampled.expect": "false"}, ) self.assertFalse(not_sampled_result.decision.is_sampled()) self.assertEqual(not_sampled_result.attributes, {}) self.assertIsNone(sampled_result.trace_state)
def test_sampling_rate(self): context = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, span_id=0x34BF92DEEFC58C92, is_remote=False, trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED), ) sampler = sampling.TraceIdRatioBased(0.5) span = trace.Span(name="sampled", context=context, parent=None, sampler=sampler) span.start() span.end() # pylint: disable=protected-access exporter = datadog.DatadogSpanExporter() datadog_spans = [ span.to_dict() for span in exporter._translate_to_datadog([span]) ] self.assertEqual(len(datadog_spans), 1) actual = [ span["metrics"].get(datadog.constants.SAMPLE_RATE_METRIC_KEY) if "metrics" in span else None for span in datadog_spans ] expected = [0.5] self.assertListEqual(actual, expected)
def test_probability_sampler_one(self): default_off = sampling.TraceIdRatioBased(1.0) self.assertTrue( default_off.should_sample( None, 0xFFFFFFFFFFFFFFFF, "span name" ).decision.is_sampled() )
def test_probability_sampler_zero(self): default_off = sampling.TraceIdRatioBased(0.0) self.assertFalse( default_off.should_sample( None, 0x0, "span name" ).decision.is_sampled() )
def test_probability_sampler(self): trace_state = trace.TraceState({"key": "value"}) sampler = sampling.TraceIdRatioBased(0.5) # Check that we sample based on the trace ID if the parent context is # null sampled_result = sampler.should_sample( None, 0x7FFFFFFFFFFFFFFF, "sampled true", attributes={"sampled.expect": "true"}, trace_state=trace_state, ) self.assertTrue(sampled_result.decision.is_sampled()) self.assertEqual(sampled_result.attributes, {"sampled.expect": "true"}) self.assertEqual(sampled_result.trace_state, trace_state) not_sampled_result = sampler.should_sample( None, 0x8000000000000000, "sampled false", attributes={"sampled.expect": "false"}, trace_state=trace_state, ) self.assertFalse(not_sampled_result.decision.is_sampled()) self.assertEqual(not_sampled_result.attributes, {}) self.assertEqual(not_sampled_result.trace_state, trace_state)
def test_service_name_fallback(self): context = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, span_id=0x34BF92DEEFC58C92, is_remote=False, trace_flags=trace_api.TraceFlags(trace_api.TraceFlags.SAMPLED), ) trace_api.get_tracer_provider().sampler = sampling.TraceIdRatioBased( 0.5) resource_with_default_name = Resource( attributes={ "key_resource": "some_resource", "service.name": "unknown_service", }) span = trace._Span( name="sampled", context=context, parent=None, resource=resource_with_default_name, ) span.start() span.end() # pylint: disable=protected-access exporter = datadog.DatadogSpanExporter(service="fallback_service_name") datadog_spans = [ span.to_dict() for span in exporter._translate_to_datadog([span]) ] self.assertEqual(len(datadog_spans), 1) span = datadog_spans[0] self.assertEqual(span["service"], "fallback_service_name")
def test_probability_sampler(self): sampler = sampling.TraceIdRatioBased(0.5) # Check that we sample based on the trace ID if the parent context is # null self.assertTrue( sampler.should_sample(None, 0x7FFFFFFFFFFFFFFF, 0xDEADBEEF, "span name").decision.is_sampled()) self.assertFalse( sampler.should_sample(None, 0x8000000000000000, 0xDEADBEEF, "span name").decision.is_sampled())