aws_xray_sdk/core/sampling/sampling_rule.py (97 lines of code) (raw):
import threading
from .reservoir import Reservoir
from aws_xray_sdk.core.utils.search_pattern import wildcard_match
class SamplingRule:
"""
Data model for a single centralized sampling rule definition.
"""
def __init__(self, name, priority, rate, reservoir_size,
host=None, method=None, path=None, service=None,
service_type=None):
self._name = name
self._priority = priority
self._rate = rate
self._can_borrow = not not reservoir_size
self._host = host
self._method = method
self._path = path
self._service = service
self._service_type = service_type
self._reservoir = Reservoir()
self._reset_statistics()
self._lock = threading.Lock()
def match(self, sampling_req):
"""
Determines whether or not this sampling rule applies to the incoming
request based on some of the request's parameters.
Any ``None`` parameter provided will be considered an implicit match.
"""
if sampling_req is None:
return False
host = sampling_req.get('host', None)
method = sampling_req.get('method', None)
path = sampling_req.get('path', None)
service = sampling_req.get('service', None)
service_type = sampling_req.get('service_type', None)
return (not host or wildcard_match(self._host, host)) \
and (not method or wildcard_match(self._method, method)) \
and (not path or wildcard_match(self._path, path)) \
and (not service or wildcard_match(self._service, service)) \
and (not service_type or wildcard_match(self._service_type, service_type))
def is_default(self):
# ``Default`` is a reserved keyword on X-Ray back-end.
return self.name == 'Default'
def snapshot_statistics(self):
"""
Take a snapshot of request/borrow/sampled count for reporting
back to X-Ray back-end by ``TargetPoller`` and reset those counters.
"""
with self._lock:
stats = {
'request_count': self.request_count,
'borrow_count': self.borrow_count,
'sampled_count': self.sampled_count,
}
self._reset_statistics()
return stats
def merge(self, rule):
"""
Migrate all stateful attributes from the old rule
"""
with self._lock:
self._request_count = rule.request_count
self._borrow_count = rule.borrow_count
self._sampled_count = rule.sampled_count
self._reservoir = rule.reservoir
rule.reservoir = None
def ever_matched(self):
"""
Returns ``True`` if this sample rule has ever been matched
with an incoming request within the reporting interval.
"""
return self._request_count > 0
def time_to_report(self):
"""
Returns ``True`` if it is time to report sampling statistics
of this rule to refresh quota information for its reservoir.
"""
return self.reservoir._time_to_report()
def increment_request_count(self):
with self._lock:
self._request_count += 1
def increment_borrow_count(self):
with self._lock:
self._borrow_count += 1
def increment_sampled_count(self):
with self._lock:
self._sampled_count += 1
def _reset_statistics(self):
self._request_count = 0
self._borrow_count = 0
self._sampled_count = 0
@property
def rate(self):
return self._rate
@rate.setter
def rate(self, v):
self._rate = v
@property
def name(self):
return self._name
@property
def priority(self):
return self._priority
@property
def reservoir(self):
return self._reservoir
@reservoir.setter
def reservoir(self, v):
self._reservoir = v
@property
def can_borrow(self):
return self._can_borrow
@property
def request_count(self):
return self._request_count
@property
def borrow_count(self):
return self._borrow_count
@property
def sampled_count(self):
return self._sampled_count