diff --git a/gstatsd/client.py b/gstatsd/client.py index f881f80..34bcf8a 100644 --- a/gstatsd/client.py +++ b/gstatsd/client.py @@ -20,10 +20,13 @@ class StatsClient(object): hostport = StatsClient.HOSTPORT self._hostport = hostport self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - + def timer(self, key, timestamp, sample_rate=1): self._send('%s:%d|ms' % (key, round(timestamp)), sample_rate) + def gauge(self, key, value, sample_rate=1): + self._send('%s:%d|g' % (key, value), sample_rate) + def increment(self, key, sample_rate=1): return self.counter(key, 1, sample_rate) @@ -85,6 +88,17 @@ class StatsTimer(object): self._started = 0 +class StatsGauge(object): + + def __init__(self, client, key, sample_rate=1): + self._client = client + self._key = key + self._sample_rate = sample_rate + + def set(self, value): + self._client.gauge(self._key, value, self._sample_rate) + + class Stats(object): def __init__(self, client): @@ -96,3 +110,5 @@ class Stats(object): def get_timer(self, key): return StatsTimer(self._client, key) + def get_gauge(self, key): + return StatsGauge(self._client, key) diff --git a/gstatsd/client_test.py b/gstatsd/client_test.py index 70958dd..0783098 100644 --- a/gstatsd/client_test.py +++ b/gstatsd/client_test.py @@ -53,6 +53,14 @@ class StatsClientTest(unittest.TestCase): self._cli.counter('foo', 1, 0.2) self.assertEquals(self._cli.packets[-1], ('foo:1|c', 0.2)) + def test_gauge(self): + self._cli.gauge('foo', 5) + self.assertEquals(self._cli.packets[-1], ('foo:5|g', 1)) + self._cli.counter('foo', -50) + self.assertEquals(self._cli.packets[-1], ('foo:-50|g', 1)) + self._cli.counter('foo', 5.9) + self.assertEquals(self._cli.packets[-1], ('foo:5.9|g', 1)) + class StatsTest(unittest.TestCase): @@ -86,4 +94,3 @@ def main(): if __name__ == '__main__': main() - diff --git a/gstatsd/service.py b/gstatsd/service.py index ae009ea..7130965 100644 --- a/gstatsd/service.py +++ b/gstatsd/service.py @@ -48,6 +48,7 @@ class Stats(object): def __init__(self): self.timers = defaultdict(list) self.counts = defaultdict(float) + self.gauges = defaultdict(float) self.percent = PERCENT self.interval = INTERVAL @@ -163,7 +164,7 @@ class StatsDaemon(object): self._flush_task = gevent.spawn(_flush_impl) # start accepting connections - self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, + self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self._sock.bind(self._bindaddr) while 1: @@ -206,12 +207,16 @@ class StatsDaemon(object): srate = float(fields[2][1:]) value = float(value if value else 1) * (1 / srate) stats.counts[key] += value + elif stype == 'g': + value = float(value if value else 1) + stats.gauges[key] = value + def main(): opts = optparse.OptionParser(description=DESCRIPTION, version=__version__, add_help_option=False) - opts.add_option('-b', '--bind', dest='bind_addr', default=':8125', + opts.add_option('-b', '--bind', dest='bind_addr', default=':8125', help="bind [host]:port (host defaults to '')") opts.add_option('-s', '--sink', dest='sink', action='append', default=[], help="a graphite service to which stats are sent ([host]:port).") @@ -239,8 +244,7 @@ def main(): sd = StatsDaemon(options.bind_addr, options.sink, options.interval, options.percent, options.verbose) sd.start() - + if __name__ == '__main__': main() - diff --git a/gstatsd/sink.py b/gstatsd/sink.py index 588c9d3..8d51a32 100644 --- a/gstatsd/sink.py +++ b/gstatsd/sink.py @@ -86,6 +86,13 @@ class GraphiteSink(Sink): buf.write('stats_counts.%s %f %d\n' % (key, val, now)) num_stats += 1 + # counter stats + gauges = stats.gauges + for key, val in gauges.iteritems(): + buf.write('stats.%s %f %d\n' % (key, val, now)) + buf.write('stats_counts.%s %f %d\n' % (key, val, now)) + num_stats += 1 + buf.write('statsd.numStats %d %d\n' % (num_stats, now)) # TODO: add support for N retries @@ -99,4 +106,3 @@ class GraphiteSink(Sink): sock.close() except Exception, ex: self.error(E_SENDFAIL % ('graphite', host, ex)) -