asyncstatsd an asynchronous statsd client library
I’ve just released asyncstatsd, a python statsd client library, fully asynchronous and based on asyncio. It’s a simple library that allows to send metrics to statsd server in a non-blocking way. For years, I was ok using jsocol/pystatsd: A Python client for statsd, but it does not support DataDog tagged metrics as their docs state:
Tagged metrics—such as those used by Datadog and Telegraf—are explicitly outside the scope of this library. Alternatives exist and are recommended. This document lays out the reasons to avoid support for tags. ~ [^1]
Unfortunately, author of alternative implementation decided to delete github repository. PyPI package is still available, but I did not want to rely on something that is not maintained anymore.
There is library provided by DataDog, but it’s not asynchronous by default.
Though it has support for UDP transport nevertheless it forces you to install requests
, a synchronous HTTP client
library. It uses thread, locks and queues - in general it’s too bloated for my taste.
Anyway, I’ve decided to write my own implementation. It’s targeted asyncio
python and for now support only UDP transport via asyncio.DatagramProtocol
. Pure statsd implementation is based on statsd specification and supports all basic metric types:
import asyncio
from asyncstatsd.client import StatsdClient
async def bar(statsd):
statsd.incr('some.counter')
statsd.timing('some.timer', 320)
with statsd.timer('some.timer'):
await asyncio.sleep(1)
async def main():
client = StatsdClient('localhost', 8125)
await client.connect()
foo(client)
await bar(client)
If you need to send tagged metrics to DataDog, you can use DatadogClient
. Implementation is informed by Getting Started with Tags
import asyncio
from asyncstatsd.client import DatadogClient
def foo(statsd):
statsd.incr('some.counter', tags=dict(tag1='value1', tag2='value2'))
statsd.timing('some.timer', 320, tags=dict(tag1='value1', tag2='value2'))
async def bar(statsd):
statsd.incr('some.counter', tags=dict(tag1='value1', tag2='value2'))
statsd.timing('some.timer', 320, tags=dict(tag1='value1', tag2='value2')
with statsd.timer('some.timer', tags=dict(tag1='value1', tag2='value2'):
await asyncio.sleep(1)
async def main():
client = DatadogClient('localhost', 8125)
await client.connect()
foo(client)
await bar(client)
For now DatadogClient
supports only pure statsd metric types with tags. I’m planning to add support for DataDog specific metrics like histogram
and distribution
in the future. Whole idea was to keep it simple and easy to extend so adding histogram
support should be as easy as:
@dataclass
class DatadogHistogramMetric(StatsdMetric):
value: float
unit: str = "h"
class DatadogClient(AbstractStatsdClient, StatsdClientBase):
...
def histogram(self, stat, value, rate=1, *, tags: Dict = {}):
self.send(DatadogHistogramMetric(stat, value, rate=rate, tags=tags))
Check it out on github: b1r3k/asyncstatsd: easy extendable asyncio-based client for sending metric to StatsD