Skip to content

Latest commit

 

History

History
86 lines (56 loc) · 2.13 KB

File metadata and controls

86 lines (56 loc) · 2.13 KB

μstats

μstats sends tagged statsd metrics with UDP. The benefits of UDP is that you can fire and forget, the beauty of statsd format is simplicity.

The recommended usecase is to first send the metrics to the stats-exporter, then let Prometheus periodically scrape data from the exporter.

ustats is a open source product by impersonate.pro

Why

Prometheus is great, the query language is simple and expressive. But the scrape behavior and "pull" model can be really annoying, especially in Python, where setting up an additional thread in web framework is cumbersome. Moreover, the Prometheus python client API is somewhat weird to me. From a pythonista's point of view, python seems to be a second-class citizen in the Prometheus ecosystem.

What I really miss from previous experience is to use the "push" model and utilize UDP's send-and-forget behavior. Unfortunately, Prometheus does not support this.

However, there is an old UDP-based metric server/protocol called statsd, which is UDP-based. And there are some extensions to the protocol that support tags, a crucial feature.

To combine the best of two worlds, we can use statsd-exporter, which simulates as a statsd server, but export metrics to an HTTP endpoint for Prometheus to scrape.

Now, all we need is a Python library to send metrics in tagged statsd format, and here comes ustats.

Tutorial

Clone

git clone https://github.com/lexiforest/ustats

Start the backend services

cd deploy
docker-compose -n metrics up

Login to Grafana, and config the backend services.

Testing

Run the example scripts in a new shell for a little while.

Add the following query in Grafana.

rate(test_api_call_sum[1m]) / rate(test_api_call_count[1m])

Now you should see the generated metrics from the example script.

Tips

My primary usage pattern is to send the

import ustats

ustats.init(prefix="test")

ustats.timer()

Asyncio is also supported.

import asyncio
import ustats

async def main():
  await ustats.ainit()

if __name__ == "__main__":
  asyncio.run(main())