Skip to content

Commit 430387f

Browse files
committed
Illustrate moving the flags from the scope to the integration
1 parent b1a0973 commit 430387f

File tree

4 files changed

+104
-29
lines changed

4 files changed

+104
-29
lines changed

sentry_sdk/flag_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
FlagData = TypedDict("FlagData", {"flag": str, "result": bool})
1010

1111

12-
DEFAULT_FLAG_CAPACITY = 100
12+
# DEFAULT_FLAG_CAPACITY = 100
1313

1414

1515
class FlagBuffer:
Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import TYPE_CHECKING
22
import sentry_sdk
33

4+
from sentry_sdk.flag_utils import FlagBuffer
45
from sentry_sdk.integrations import DidNotEnable, Integration
56

67
try:
@@ -16,35 +17,55 @@
1617
raise DidNotEnable("OpenFeature is not installed")
1718

1819

20+
DEFAULT_FLAG_CAPACITY = 100
21+
22+
1923
class OpenFeatureIntegration(Integration):
2024
identifier = "openfeature"
2125

26+
def __init__(self, max_flags=DEFAULT_FLAG_CAPACITY):
27+
# type: (OpenFeatureIntegration, int) -> None
28+
self._max_flags = max_flags
29+
self._flags = None # type: Optional[FlagBuffer]
30+
2231
@staticmethod
2332
def setup_once():
2433
# type: () -> None
25-
def error_processor(event, exc_info):
26-
# type: (Event, ExcInfo) -> Optional[Event]
27-
scope = sentry_sdk.get_current_scope()
28-
event["contexts"]["flags"] = {"values": scope.flags.get()}
29-
return event
30-
31-
scope = sentry_sdk.get_current_scope()
32-
scope.add_error_processor(error_processor)
33-
3434
# Register the hook within the global openfeature hooks list.
3535
api.add_hooks(hooks=[OpenFeatureHook()])
3636

37+
@property
38+
def flags(self):
39+
# type: () -> FlagBuffer
40+
if self._flags is None:
41+
max_flags = self._max_flags or DEFAULT_FLAG_CAPACITY
42+
self._flags = FlagBuffer(capacity=max_flags)
43+
return self._flags
3744

38-
class OpenFeatureHook(Hook):
3945

46+
class OpenFeatureHook(Hook):
4047
def after(self, hook_context, details, hints):
4148
# type: (HookContext, FlagEvaluationDetails[bool], HookHints) -> None
49+
integration = sentry_sdk.get_client().get_integration(OpenFeatureIntegration)
50+
if integration is None:
51+
return
52+
4253
if isinstance(details.value, bool):
43-
flags = sentry_sdk.get_current_scope().flags
44-
flags.set(details.flag_key, details.value)
54+
integration.flags.set(details.flag_key, details.value)
4555

4656
def error(self, hook_context, exception, hints):
4757
# type: (HookContext, Exception, HookHints) -> None
58+
integration = sentry_sdk.get_client().get_integration(OpenFeatureIntegration)
59+
if integration is None:
60+
return
61+
62+
def error_processor(event, exc_info):
63+
# type: (Event, ExcInfo) -> Optional[Event]
64+
event["contexts"]["flags"] = {"values": integration.flags.get()}
65+
return event
66+
67+
scope = sentry_sdk.get_current_scope()
68+
scope.add_error_processor(error_processor)
69+
4870
if isinstance(hook_context.default_value, bool):
49-
flags = sentry_sdk.get_current_scope().flags
50-
flags.set(hook_context.flag_key, hook_context.default_value)
71+
integration.flags.set(hook_context.flag_key, hook_context.default_value)

sentry_sdk/scope.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
from sentry_sdk.attachments import Attachment
1313
from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS, FALSE_VALUES, INSTRUMENTER
14-
from sentry_sdk.flag_utils import FlagBuffer, DEFAULT_FLAG_CAPACITY
14+
15+
# from sentry_sdk.flag_utils import FlagBuffer, DEFAULT_FLAG_CAPACITY
1516
from sentry_sdk.profiler.continuous_profiler import try_autostart_continuous_profiler
1617
from sentry_sdk.profiler.transaction_profiler import Profile
1718
from sentry_sdk.session import Session
@@ -193,7 +194,7 @@ class Scope:
193194
"client",
194195
"_type",
195196
"_last_event_id",
196-
"_flags",
197+
# "_flags",
197198
)
198199

199200
def __init__(self, ty=None, client=None):
@@ -251,7 +252,7 @@ def __copy__(self):
251252

252253
rv._last_event_id = self._last_event_id
253254

254-
rv._flags = copy(self._flags)
255+
# rv._flags = copy(self._flags)
255256

256257
return rv
257258

@@ -689,7 +690,7 @@ def clear(self):
689690

690691
# self._last_event_id is only applicable to isolation scopes
691692
self._last_event_id = None # type: Optional[str]
692-
self._flags = None # type: Optional[FlagBuffer]
693+
# self._flags = None # type: Optional[FlagBuffer]
693694

694695
@_attr_setter
695696
def level(self, value):
@@ -1551,16 +1552,16 @@ def __repr__(self):
15511552
self._type,
15521553
)
15531554

1554-
@property
1555-
def flags(self):
1556-
# type: () -> FlagBuffer
1557-
if self._flags is None:
1558-
max_flags = (
1559-
self.get_client().options["_experiments"].get("max_flags")
1560-
or DEFAULT_FLAG_CAPACITY
1561-
)
1562-
self._flags = FlagBuffer(capacity=max_flags)
1563-
return self._flags
1555+
# @property
1556+
# def flags(self):
1557+
# # type: () -> FlagBuffer
1558+
# if self._flags is None:
1559+
# max_flags = (
1560+
# self.get_client().options["_experiments"].get("max_flags")
1561+
# or DEFAULT_FLAG_CAPACITY
1562+
# )
1563+
# self._flags = FlagBuffer(capacity=max_flags)
1564+
# return self._flags
15641565

15651566

15661567
@contextmanager

tests/integrations/openfeature/test_openfeature.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,65 @@
11
import asyncio
22
import concurrent.futures as cf
3+
34
import sentry_sdk
45

56
from openfeature import api
67
from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider
78
from sentry_sdk.integrations.openfeature import OpenFeatureIntegration
89

910

11+
def test_openfeature_integration_flags_on_integration(sentry_init, capture_events):
12+
sentry_init(integrations=[OpenFeatureIntegration()])
13+
14+
flags = {
15+
"hello": InMemoryFlag("on", {"on": True, "off": False}),
16+
"world": InMemoryFlag("off", {"on": True, "off": False}),
17+
}
18+
api.set_provider(InMemoryProvider(flags))
19+
20+
client = api.get_client()
21+
client.get_boolean_value("hello", default_value=False)
22+
client.get_boolean_value("world", default_value=False)
23+
client.get_boolean_value("other", default_value=True)
24+
25+
events = capture_events()
26+
27+
sentry_sdk.capture_exception(Exception("test"))
28+
29+
(event,) = events
30+
31+
assert event["contexts"]["flags"]["values"] == [
32+
{"flag": "hello", "result": True},
33+
{"flag": "world", "result": False},
34+
{"flag": "other", "result": True},
35+
]
36+
37+
38+
def test_openfeature_integration_max_flags(sentry_init, capture_events):
39+
sentry_init(integrations=[OpenFeatureIntegration(max_flags=2)])
40+
41+
flags = {
42+
"hello": InMemoryFlag("on", {"on": True, "off": False}),
43+
"world": InMemoryFlag("off", {"on": True, "off": False}),
44+
}
45+
api.set_provider(InMemoryProvider(flags))
46+
47+
client = api.get_client()
48+
client.get_boolean_value("hello", default_value=False)
49+
client.get_boolean_value("world", default_value=False)
50+
client.get_boolean_value("other", default_value=True)
51+
52+
events = capture_events()
53+
54+
sentry_sdk.capture_exception(Exception("test"))
55+
56+
(event,) = events
57+
assert event["contexts"]["flags"]["values"] == [
58+
{"flag": "world", "result": False},
59+
{"flag": "other", "result": True},
60+
]
61+
62+
1063
def test_openfeature_integration(sentry_init):
1164
sentry_init(integrations=[OpenFeatureIntegration()])
1265

0 commit comments

Comments
 (0)