-
Notifications
You must be signed in to change notification settings - Fork 591
Expand file tree
/
Copy pathfeature_flags.py
More file actions
66 lines (50 loc) · 2.15 KB
/
feature_flags.py
File metadata and controls
66 lines (50 loc) · 2.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import copy
import sentry_sdk
from sentry_sdk._lru_cache import LRUCache
from sentry_sdk.tracing import Span
from threading import Lock
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from typing import TypedDict
FlagData = TypedDict("FlagData", {"flag": str, "result": bool})
DEFAULT_FLAG_CAPACITY = 100
class FlagBuffer:
def __init__(self, capacity: int) -> None:
self.capacity = capacity
self.lock = Lock()
# Buffer is private. The name is mangled to discourage use. If you use this attribute
# directly you're on your own!
self.__buffer = LRUCache(capacity)
def clear(self) -> None:
self.__buffer = LRUCache(self.capacity)
def __deepcopy__(self, memo: "dict[int, Any]") -> "FlagBuffer":
with self.lock:
buffer = FlagBuffer(self.capacity)
buffer.__buffer = copy.deepcopy(self.__buffer, memo)
return buffer
def get(self) -> "list[FlagData]":
with self.lock:
return [
{"flag": key, "result": value} for key, value in self.__buffer.get_all()
]
def set(self, flag: str, result: bool) -> None:
if isinstance(result, FlagBuffer):
# If someone were to insert `self` into `self` this would create a circular dependency
# on the lock. This is of course a deadlock. However, this is far outside the expected
# usage of this class. We guard against it here for completeness and to document this
# expected failure mode.
raise ValueError(
"FlagBuffer instances can not be inserted into the dictionary."
)
with self.lock:
self.__buffer.set(flag, result)
def add_feature_flag(flag: str, result: bool) -> None:
"""
Records a flag and its value to be sent on subsequent error events.
We recommend you do this on flag evaluations. Flags are buffered per Sentry scope.
"""
flags = sentry_sdk.get_isolation_scope().flags
flags.set(flag, result)
span = sentry_sdk.get_current_span()
if span and isinstance(span, Span):
span.set_flag(f"flag.evaluation.{flag}", result)