Preview: feature_flags.py
Size: 2.50 KB
/proc/thread-self/root/opt/hc_python/lib64/python3.12/site-packages/sentry_sdk/feature_flags.py
import copy
from threading import Lock
from typing import TYPE_CHECKING, Any
import sentry_sdk
from sentry_sdk._lru_cache import LRUCache
from sentry_sdk.tracing import Span
from sentry_sdk.tracing_utils import has_span_streaming_enabled
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.
"""
client = sentry_sdk.get_client()
flags = sentry_sdk.get_isolation_scope().flags
flags.set(flag, result)
if has_span_streaming_enabled(client.options):
span = sentry_sdk.traces.get_current_span()
if span and isinstance(span, sentry_sdk.traces.StreamedSpan):
span.set_attribute(f"flag.evaluation.{flag}", result)
else:
span = sentry_sdk.get_current_span()
if span and isinstance(span, Span):
span.set_flag(f"flag.evaluation.{flag}", result)
Directory Contents
Dirs: 5 × Files: 36