Repository: DataDog/dd-trace-py

Issue:
RateSampler samples at 100% when set to 0%
When testing impact of different sample rates, we set the sample rate to `0.0`, at which point we started seeing 100% of traces sampled:

https://github.com/DataDog/dd-trace-py/blob/3fe328a0a12a7d107bdf85ba9073c219be20174b/ddtrace/sampler.py#L51-L53

Instead, I would expect this condition to check `<` rather than `<=` as 0 is a valid sampling rate. 


Discussion:
Yep, AFAICT this is a bug (perhaps the assumption was that setting a sample rate to 0 wasn't going to be a use-case). Looks like an easy fix.

Resolving patch:
diff --git a/ddtrace/internal/writer.py b/ddtrace/internal/writer.py
--- a/ddtrace/internal/writer.py
+++ b/ddtrace/internal/writer.py
@@ -257,14 +257,17 @@ def _send_payload(self, payload, count):
         elif self._priority_sampler or isinstance(self._sampler, BasePrioritySampler):
             result_traces_json = response.get_json()
             if result_traces_json and "rate_by_service" in result_traces_json:
-                if self._priority_sampler:
-                    self._priority_sampler.update_rate_by_service_sample_rates(
-                        result_traces_json["rate_by_service"],
-                    )
-                if isinstance(self._sampler, BasePrioritySampler):
-                    self._sampler.update_rate_by_service_sample_rates(
-                        result_traces_json["rate_by_service"],
-                    )
+                try:
+                    if self._priority_sampler:
+                        self._priority_sampler.update_rate_by_service_sample_rates(
+                            result_traces_json["rate_by_service"],
+                        )
+                    if isinstance(self._sampler, BasePrioritySampler):
+                        self._sampler.update_rate_by_service_sample_rates(
+                            result_traces_json["rate_by_service"],
+                        )
+                except ValueError:
+                    log.error("sample_rate is negative, cannot update the rate samplers")
 
     def write(self, spans):
         # Start the AgentWriter on first write.
diff --git a/ddtrace/sampler.py b/ddtrace/sampler.py
--- a/ddtrace/sampler.py
+++ b/ddtrace/sampler.py
@@ -53,9 +53,8 @@ class RateSampler(BaseSampler):
     """
 
     def __init__(self, sample_rate=1):
-        if sample_rate <= 0:
-            log.error("sample_rate is negative or null, disable the Sampler")
-            sample_rate = 1
+        if sample_rate < 0:
+            raise ValueError("sample_rate of {} is negative".format(sample_rate))
         elif sample_rate > 1:
             sample_rate = 1
 


Test patch:
diff --git a/tests/tracer/test_sampler.py b/tests/tracer/test_sampler.py
--- a/tests/tracer/test_sampler.py
+++ b/tests/tracer/test_sampler.py
@@ -103,6 +103,17 @@ def test_deterministic_behavior(self):
                     other_span
                 ), "sampling should give the same result for a given trace_id"
 
+    def test_negative_sample_rate_raises_error(self):
+        tracer = get_dummy_tracer()
+        with pytest.raises(ValueError, match="sample_rate of -0.5 is negative"):
+            tracer.sampler = RateSampler(sample_rate=-0.5)
+
+    def test_sample_rate_0_does_not_reset_to_1(self):
+        # Regression test for case where a sample rate of 0 caused the sample rate to be reset to 1
+        tracer = get_dummy_tracer()
+        tracer.sampler = RateSampler(sample_rate=0)
+        assert tracer.sampler.sample_rate == 0
+
 
 class RateByServiceSamplerTest(unittest.TestCase):
     def test_default_key(self):