Skip to content

Commit 91fd291

Browse files
authored
fix sampling (#413)
added new condition in kong test statsig-io/kong#3487 ![Screenshot 2025-03-03 at 3 09 14 PM](https://github.com/user-attachments/assets/6c17a7be-c883-4dca-9889-eed4bf38502e)
1 parent 7654b01 commit 91fd291

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

statsig/config_evaluation.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ def __init__(self,
1717
sample_rate=None,
1818
user=None,
1919
forward_all_exposures=False,
20-
id_type=""):
20+
id_type="",
21+
analytical_condition=False,
22+
seen_analytical_gates=False
23+
):
2124
if boolean_value is None:
2225
boolean_value = False
2326
self.boolean_value = boolean_value
@@ -45,3 +48,5 @@ def __init__(self,
4548
self.user = user
4649
self.forward_all_exposures = forward_all_exposures
4750
self.version = version
51+
self.analytical_condition = analytical_condition
52+
self.seen_analytical_gates = seen_analytical_gates

statsig/evaluator.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def __finalize_exposures(self, end_result):
303303
def __evaluate_rule(self, user, rule, end_result):
304304
total_eval_result = True
305305
for condition in rule.get("conditions", []):
306-
eval_result = self.__evaluate_condition(user, condition, end_result)
306+
eval_result = self.__evaluate_condition(user, condition, end_result, rule.get("samplingRate", None))
307307
if not eval_result:
308308
total_eval_result = False
309309
end_result.boolean_value = total_eval_result
@@ -325,13 +325,14 @@ def __evaluate_delegate(self, user, rule, end_result):
325325
end_result.allocated_experiment = config_delegate
326326
return end_result
327327

328-
def __evaluate_condition(self, user, condition, end_result):
328+
def __evaluate_condition(self, user, condition, end_result, sampling_rate=None):
329329
value = None
330330
type = condition.get("type", "").upper()
331331
target = condition.get("targetValue")
332332
field = condition.get("field", "")
333333
id_Type = condition.get("idType", "userID")
334334
if type == "PUBLIC":
335+
end_result.analytical_condition = sampling_rate is None
335336
return True
336337
if type in ("FAIL_GATE", "PASS_GATE"):
337338
self.check_gate(user, target, end_result, True)
@@ -343,11 +344,16 @@ def __evaluate_condition(self, user, condition, end_result):
343344
}
344345

345346
end_result.secondary_exposures.append(new_exposure)
347+
if end_result.analytical_condition and isinstance(target, str) and not target.startswith("segment:"):
348+
end_result.seen_analytical_gates = True
346349

347350
pass_gate = end_result.boolean_value if type == "PASS_GATE" else not end_result.boolean_value
351+
352+
end_result.analytical_condition = sampling_rate is None
348353
return pass_gate
349354
if type in ("MULTI_PASS_GATE", "MULTI_FAIL_GATE"):
350355
if target is None or len(target) == 0:
356+
end_result.analytical_condition = sampling_rate is None
351357
return False
352358
pass_gate = False
353359
for gate in target:
@@ -359,10 +365,14 @@ def __evaluate_condition(self, user, condition, end_result):
359365
"ruleID": other_result.rule_id
360366
}
361367
end_result.secondary_exposures.append(new_exposure)
368+
if end_result.analytical_condition and isinstance(target, str) and not target.startswith("segment:"):
369+
end_result.seen_analytical_gates = True
362370

363371
pass_gate = pass_gate or other_result.boolean_value if type == "MULTI_PASS_GATE" else pass_gate or not other_result.boolean_value
364372
if pass_gate:
365373
break
374+
375+
end_result.analytical_condition = sampling_rate is None
366376
return pass_gate
367377
if type == "IP_BASED":
368378
value = self.__get_from_user(user, field)
@@ -373,6 +383,7 @@ def __evaluate_condition(self, user, condition, end_result):
373383
self._country_lookup = CountryLookup()
374384
value = self._country_lookup.lookupStr(ip)
375385
if value is None:
386+
end_result.analytical_condition = sampling_rate is None
376387
return False
377388
elif type == "UA_BASED":
378389
value = self.__get_from_user(user, field)
@@ -394,6 +405,8 @@ def __evaluate_condition(self, user, condition, end_result):
394405
elif type == "UNIT_ID":
395406
value = self.__get_unit_id(user, id_Type)
396407

408+
end_result.analytical_condition = sampling_rate is None
409+
397410
op = condition.get("operator")
398411
user_bucket = condition.get("user_bucket")
399412
if op == "gt":

statsig/statsig_logger.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ def __determine_sampling(self, type: EntityType, name: str, result: _ConfigEvalu
277277
self._sampling_key_set.add(samplingSetKey)
278278
return True, None, None
279279

280+
if result.seen_analytical_gates:
281+
return True, None, None
282+
280283
should_sample = result.sample_rate is not None or result.rule_id in special_case_rules
281284
if not should_sample:
282285
return True, None, None

0 commit comments

Comments
 (0)