class DogStatsdMonitoring(AbstractMonitoring): def __init__(self, config): super().__init__(config) self.client = DogStatsd() def send(self, tags, value): if len(tags) != 3: raise AssertionError( "Datadog monitoring implementation needs 3 tags: 'name', 'what' and 'backup_name'" ) name, what, backup_name = tags metric = '{name}.{what}'.format(name=name, what=what) backup_name_tag = 'backup_name:{}'.format(backup_name) # The backup_name would be a rather high cardinality metrics series if backups are at all frequent. # This could be a expensive metric so backup_name is droppped from the tags sent by default if medusa.utils.evaluate_boolean(self.config.send_backup_name_tag): self.client.gauge(metric, value, tags=[backup_name_tag]) else: self.client.gauge(metric, value)
class DatadogStatsClient: """Statsd compliant datadog client.""" def __init__(self, host: str = 'localhost', port: int = 8125, prefix: str = 'faust-app', rate: float = 1.0, **kwargs: Any) -> None: self.client = DogStatsd(host=host, port=port, namespace=prefix, **kwargs) self.rate = rate self.sanitize_re = re.compile(r'[^0-9a-zA-Z_]') self.re_substitution = '_' def gauge(self, metric: str, value: float, labels: Dict = None) -> None: self.client.gauge( metric, value=value, tags=self._encode_labels(labels), sample_rate=self.rate, ) def increment(self, metric: str, value: float = 1.0, labels: Dict = None) -> None: self.client.increment( metric, value=value, tags=self._encode_labels(labels), sample_rate=self.rate, ) def incr(self, metric: str, count: int = 1) -> None: """Statsd compatibility.""" self.increment(metric, value=count) def decrement(self, metric: str, value: float = 1.0, labels: Dict = None) -> float: return self.client.decrement( metric, value=value, tags=self._encode_labels(labels), sample_rate=self.rate, ) def decr(self, metric: str, count: float = 1.0) -> None: """Statsd compatibility.""" self.decrement(metric, value=count) def timing(self, metric: str, value: float, labels: Dict = None) -> None: self.client.timing( metric, value=value, tags=self._encode_labels(labels), sample_rate=self.rate, ) def timed(self, metric: str = None, labels: Dict = None, use_ms: bool = None) -> float: return self.client.timed( metric=metric, tags=self._encode_labels(labels), sample_rate=self.rate, use_ms=use_ms, ) def histogram(self, metric: str, value: float, labels: Dict = None) -> None: self.client.histogram( metric, value=value, tags=self._encode_labels(labels), sample_rate=self.rate, ) def _encode_labels(self, labels: Optional[Dict]) -> Optional[List[str]]: def sanitize(s: str) -> str: return self.sanitize_re.sub(self.re_substitution, str(s)) return [f'{sanitize(k)}:{sanitize(v)}' for k, v in labels.items()] if labels else None
class DogStatsdAdapter(object): """ A wrapper around DogStatsd that supports the full statsd.StatsClient interface Note that `tags` is available on all these methods, but this is not supported by statsd.StatsClient. It has been added, but should only be used when you are CERTAIN that you will be using this class (or something similar) """ def __init__(self, host='localhost', port=8125, prefix=None, maxudpsize=512, ipv6=False): if ipv6: _log.warning("DogStatsdAdapter() was 'ipv6'. This is ignored") self._dd_client = DogStatsd(host=host, port=port, namespace=prefix, max_buffer_size=maxudpsize) def timer(self, stat, rate=1, tags=None): self._dd_client.timed(metric=stat, sample_rate=rate, use_ms=True, tags=tags) def timing(self, stat, delta, rate=1, tags=None): """Send new timing information. `delta` is in milliseconds.""" self._dd_client.timing(metric=stat, value=delta, sample_rate=rate, tags=tags) def incr(self, stat, count=1, rate=1, tags=None): """Increment a stat by `count`.""" self._dd_client.increment(metric=stat, value=count, sample_rate=rate, tags=tags) def decr(self, stat, count=1, rate=1, tags=None): """Decrement a stat by `count`.""" self._dd_client.decrement(metric=stat, value=count, sample_rate=rate, tags=tags) def gauge(self, stat, value, rate=1, delta=False, tags=None): """Set a gauge value.""" self._dd_client.gauge(metric=stat, value=value, sample_rate=rate, tags=tags) if delta: _log.warning( "DogStatsdAdapter was passed a gauge with 'delta' set. This is ignored in datadog" ) def set(self, stat, value, rate=1, tags=None): """Set a set value.""" self._dd_client.set(metric=stat, value=value, sample_rate=rate, tags=tags) def histogram(self, stat, value, rate=1, tags=None): """ Sample a histogram value, optionally setting tags and a sample rate. This is not supported by statsd.StatsClient. Use with caution! """ self._dd_client.set(metric=stat, value=value, sample_rate=rate, tags=tags)
class DogStatsdMetrics(Metrics): def __init__(self, id, prefix=None, tags=None, host="127.0.0.1", port=8125): self.id = id self.prefix = prefix self.tags = tags or {} self.host = host self.port = port self.tags["instance"] = id def setup(self): from datadog.dogstatsd import DogStatsd self.client = DogStatsd(host=self.host, port=self.port) def gauge(self, metric, value, tags=None, sample_rate=1): self.client.gauge( self._get_key(metric), value, sample_rate=sample_rate, tags=self._get_tags(tags), ) def increment(self, metric, value=1, tags=None, sample_rate=1): self.client.increment( self._get_key(metric), value, sample_rate=sample_rate, tags=self._get_tags(tags), ) def decrement(self, metric, value=1, tags=None, sample_rate=1): self.client.decrement( self._get_key(metric), value, sample_rate=sample_rate, tags=self._get_tags(tags), ) def histogram(self, metric, value, tags=None, sample_rate=1): self.client.histogram( self._get_key(metric), value, sample_rate=sample_rate, tags=self._get_tags(tags), ) def timing(self, metric, value, tags=None, sample_rate=1): self.client.timing( self._get_key(metric), value, sample_rate=sample_rate, tags=self._get_tags(tags), ) def timed(self, metric, tags=None, sample_rate=1, use_ms=None): self.client.timed( self._get_key(metric), sample_rate=sample_rate, tags=self._get_tags(tags), use_ms=use_ms, )