metrics.py (4131B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\datadog\threadstats\metrics.py 2 from collections import defaultdict 3 import random 4 import itertools 5 from datadog.util.compat import iternext 6 7 class Metric(object): 8 9 def add_point(self, value): 10 raise NotImplementedError() 11 12 def flush(self, timestamp): 13 raise NotImplementedError() 14 15 16 class Gauge(Metric): 17 stats_tag = 'g' 18 19 def __init__(self, name, tags, host): 20 self.name = name 21 self.tags = tags 22 self.host = host 23 self.value = None 24 25 def add_point(self, value): 26 self.value = value 27 28 def flush(self, timestamp): 29 return [(timestamp, 30 self.value, 31 self.name, 32 self.tags, 33 self.host)] 34 35 36 class Counter(Metric): 37 stats_tag = 'c' 38 39 def __init__(self, name, tags, host): 40 self.name = name 41 self.tags = tags 42 self.host = host 43 self.count = [] 44 45 def add_point(self, value): 46 self.count.append(value) 47 48 def flush(self, timestamp): 49 count = sum(self.count, 0) 50 return [(timestamp, 51 count, 52 self.name, 53 self.tags, 54 self.host)] 55 56 57 class Histogram(Metric): 58 stats_tag = 'h' 59 60 def __init__(self, name, tags, host): 61 self.name = name 62 self.tags = tags 63 self.host = host 64 self.max = float('-inf') 65 self.min = float('inf') 66 self.sum = [] 67 self.iter_counter = itertools.count() 68 self.count = iternext(self.iter_counter) 69 self.sample_size = 1000 70 self.samples = [] 71 self.percentiles = [0.75, 72 0.85, 73 0.95, 74 0.99] 75 76 def add_point(self, value): 77 self.max = self.max if self.max > value else value 78 self.min = self.min if self.min < value else value 79 self.sum.append(value) 80 if self.count < self.sample_size: 81 self.samples.append(value) 82 else: 83 self.samples[random.randrange(0, self.sample_size)] = value 84 self.count = iternext(self.iter_counter) 85 86 def flush(self, timestamp): 87 if not self.count: 88 return [] 89 metrics = [(timestamp, 90 self.min, 91 '%s.min' % self.name, 92 self.tags, 93 self.host), 94 (timestamp, 95 self.max, 96 '%s.max' % self.name, 97 self.tags, 98 self.host), 99 (timestamp, 100 self.count, 101 '%s.count' % self.name, 102 self.tags, 103 self.host), 104 (timestamp, 105 self.average(), 106 '%s.avg' % self.name, 107 self.tags, 108 self.host)] 109 length = len(self.samples) 110 self.samples.sort() 111 for p in self.percentiles: 112 val = self.samples[int(round(p * length - 1))] 113 name = '%s.%spercentile' % (self.name, int(p * 100)) 114 metrics.append((timestamp, 115 val, 116 name, 117 self.tags, 118 self.host)) 119 120 return metrics 121 122 def average(self): 123 sum_metrics = sum(self.sum, 0) 124 return float(sum_metrics) / self.count 125 126 127 class Timing(Histogram): 128 stats_tag = 'ms' 129 130 131 class MetricsAggregator(object): 132 133 def __init__(self, roll_up_interval = 10): 134 self._metrics = defaultdict(lambda : {}) 135 self._roll_up_interval = roll_up_interval 136 137 def add_point(self, metric, tags, timestamp, value, metric_class, sample_rate = 1, host = None): 138 interval = timestamp - timestamp % self._roll_up_interval 139 key = (metric, host, tuple(sorted(tags)) if tags else None) 140 if key not in self._metrics[interval]: 141 self._metrics[interval][key] = metric_class(metric, tags, host) 142 self._metrics[interval][key].add_point(value) 143 144 def flush(self, timestamp): 145 interval = timestamp - timestamp % self._roll_up_interval 146 past_intervals = [ i for i in self._metrics.keys() if i < interval ] 147 metrics = [] 148 for i in past_intervals: 149 for m in list(self._metrics.pop(i).values()): 150 metrics += m.flush(i) 151 152 return metrics