Skip to content

Commit c29f907

Browse files
committed
Include extra details in $feature_flag_called events
1 parent c5e4ef7 commit c29f907

File tree

3 files changed

+57
-37
lines changed

3 files changed

+57
-37
lines changed

posthog/client.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -847,16 +847,10 @@ def get_feature_flag(
847847
flag_was_locally_evaluated = response is not None
848848
if not flag_was_locally_evaluated and not only_evaluate_locally:
849849
try:
850-
feature_flags = self.get_feature_variants(
851-
distinct_id,
852-
groups=groups,
853-
person_properties=person_properties,
854-
group_properties=group_properties,
855-
disable_geoip=disable_geoip,
850+
flag_details, request_id = self._get_feature_flag_details_from_decide(
851+
key, distinct_id, groups, person_properties, group_properties, disable_geoip
856852
)
857-
response = feature_flags.get(key)
858-
if response is None:
859-
response = False
853+
response = flag_details.get_value() if flag_details else False
860854
self.log.debug(f"Successfully computed flag remotely: #{key} -> #{response}")
861855
except Exception as e:
862856
self.log.exception(f"[FEATURE FLAGS] Unable to get flag remotely: {e}")
@@ -871,7 +865,7 @@ def get_feature_flag(
871865
groups,
872866
disable_geoip,
873867
request_id,
874-
flag_details
868+
flag_details,
875869
)
876870

877871
return response
@@ -943,20 +937,15 @@ def get_feature_flag_payload(
943937
flag_was_locally_evaluated = payload is not None
944938
if not flag_was_locally_evaluated and not only_evaluate_locally:
945939
try:
946-
responses_and_payloads = self.get_feature_flags_and_payloads(
947-
distinct_id, groups, person_properties, group_properties, disable_geoip
940+
flag_details, request_id = self._get_feature_flag_details_from_decide(
941+
key, distinct_id, groups, person_properties, group_properties, disable_geoip
948942
)
949-
featureFlags = responses_and_payloads["featureFlags"]
950-
if featureFlags is not None:
951-
response = featureFlags.get(key, None)
952-
953-
featureFlagPayloads = responses_and_payloads["featureFlagPayloads"]
954-
if featureFlagPayloads is not None:
955-
payload = featureFlagPayloads.get(str(key), None)
943+
payload = flag_details.metadata.payload if flag_details else None
944+
response = flag_details.get_value() if flag_details else False
956945
except Exception as e:
957946
self.log.exception(f"[FEATURE FLAGS] Unable to get feature flags and payloads: {e}")
958947

959-
if (send_feature_flag_events):
948+
if send_feature_flag_events:
960949
self._capture_feature_flag_called(
961950
distinct_id,
962951
key,
@@ -966,11 +955,29 @@ def get_feature_flag_payload(
966955
groups,
967956
disable_geoip,
968957
request_id,
969-
flag_details
958+
flag_details,
970959
)
971960

972961
return payload
973962

963+
def _get_feature_flag_details_from_decide(
964+
self,
965+
key: str,
966+
distinct_id: str,
967+
groups: dict[str, str],
968+
person_properties: dict[str, str],
969+
group_properties: dict[str, str],
970+
disable_geoip: bool | None,
971+
) -> tuple[FeatureFlag | None, str]:
972+
"""
973+
Calls /decide and returns the flag details and request id
974+
"""
975+
resp_data = self.get_decide(distinct_id, groups, person_properties, group_properties, disable_geoip)
976+
request_id = resp_data.get("requestId")
977+
flags = resp_data.get("flags")
978+
flag_details = flags.get(key)
979+
return flag_details, request_id
980+
974981
def _capture_feature_flag_called(
975982
self,
976983
distinct_id: str,
@@ -1006,7 +1013,7 @@ def _capture_feature_flag_called(
10061013
properties["$feature_flag_version"] = flag_details.metadata.version
10071014
if flag_details.metadata.id:
10081015
properties["$feature_flag_id"] = flag_details.metadata.id
1009-
1016+
10101017
self.capture(
10111018
distinct_id,
10121019
"$feature_flag_called",

posthog/test/test_feature_flags.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2393,6 +2393,8 @@ def test_capture_is_called_with_flag_details_and_payload(self, patch_decide, pat
23932393
"enabled": True,
23942394
"variant": None,
23952395
"reason": {
2396+
"code": "matched_condition",
2397+
"condition_index": 0,
23962398
"description": "Matched condition set 1",
23972399
},
23982400
"metadata": {
@@ -2413,9 +2415,9 @@ def test_capture_is_called_with_flag_details_and_payload(self, patch_decide, pat
24132415
"$feature_flag_called",
24142416
{
24152417
"$feature_flag": "decide-flag-with-payload",
2416-
"$feature_flag_response": None,
2418+
"$feature_flag_response": True,
24172419
"locally_evaluated": False,
2418-
"$feature/decide-flag-with-payload": None,
2420+
"$feature/decide-flag-with-payload": True,
24192421
"$feature_flag_reason": "Matched condition set 1",
24202422
"$feature_flag_id": 23,
24212423
"$feature_flag_version": 42,

posthog/types.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ class FlagReason:
99
condition_index: int
1010
description: str
1111

12+
@classmethod
13+
def from_json(cls, resp: Any) -> "FlagReason":
14+
if not resp:
15+
return None
16+
return cls(
17+
code=resp.get("code", ""),
18+
condition_index=resp.get("condition_index", 0),
19+
description=resp.get("description", "")
20+
)
21+
1222

1323
@dataclass(frozen=True)
1424
class FlagMetadata:
@@ -17,6 +27,16 @@ class FlagMetadata:
1727
version: int
1828
description: str
1929

30+
@classmethod
31+
def from_json(cls, resp: Any) -> "FlagMetadata":
32+
if not resp:
33+
return None
34+
return cls(
35+
id=resp.get("id", 0),
36+
payload=resp.get("payload"),
37+
version=resp.get("version", 0),
38+
description=resp.get("description", "")
39+
)
2040

2141
@dataclass(frozen=True)
2242
class LegacyFlagMetadata:
@@ -39,26 +59,17 @@ def get_value(self) -> FlagValue:
3959
def from_json(cls, resp: Any) -> "FeatureFlag":
4060
reason = None
4161
if resp.get("reason"):
42-
reason = FlagReason(
43-
code=resp["reason"].get("code", ""),
44-
condition_index=resp["reason"].get("condition_index", 0),
45-
description=resp["reason"].get("description", "")
46-
)
62+
reason = FlagReason.from_json(resp.get("reason"))
4763

4864
metadata = None
4965
if resp.get("metadata"):
50-
metadata = FlagMetadata(
51-
id=resp["metadata"].get("id", 0),
52-
payload=resp["metadata"].get("payload"),
53-
version=resp["metadata"].get("version", 0),
54-
description=resp["metadata"].get("description", "")
55-
)
66+
metadata = FlagMetadata.from_json(resp.get("metadata"))
5667
else:
5768
metadata = LegacyFlagMetadata(payload=None)
5869

5970
return cls(
60-
key=resp["key"],
61-
enabled=resp["enabled"],
71+
key=resp.get("key"),
72+
enabled=resp.get("enabled"),
6273
variant=resp.get("variant"),
6374
reason=reason,
6475
metadata=metadata

0 commit comments

Comments
 (0)