Package: dogstatsd-collector
dogstatsd-collectoris a library to make it easy to collect DataDog-style
StatsDcountersandhistogramswith tags and control when they are flushed. It
gives you a drop-in wrapper for theDogStatsDlibrary for counters and
histograms and allows you to defer flushing the metrics until you choose to. This
capability enables you to collect StatsD metrics at arbitrary granularity, for
example on a per-web request or per-job basis (instead of the per-flush
interval basis).Counters and histograms are tracked separately for each metric series (unique
set of tag key-value pairs) and a single metric is emitted for each series when
the collector is flushed. You don’t have to think about tracking your metric
series separately; you just use theDogstatsdCollectorobject as you would the
normalDogStatsDobject, and flush when you’re ready; the library will take
care of emitting all the series for you.Free software: BSD 3-Clause LicenseInstallationpip install dogstatsd-collectorExample UsageImagine you want to track a distribution of the number of queries issued by
requests to your webapp, and tag them by which database is queried and which
verb is used. You collect the following metrics as you issue your queries:collector=DogstatsdCollector(dogstatsd)...collector.histogram('query',tags=['database:master','verb:insert'])collector.histogram('query',tags=['database:master','verb:update'])collector.histogram('query',tags=['database:master','verb:update'])collector.histogram('query',tags=['database:replica','verb:select'])collector.histogram('query',tags=['database:replica','verb:select'])Then, at the end of your web request, when you flush the collector, the
following metrics will be pushed toDogStatsD(shown in DogStatsD datagram
format):collector.flush()# query:1|h|#database:master,verb:insert# query:2|h|#database:master,verb:update# query:2|h|#database:replica,verb:selectBase TagsThe collector object also supports specifying a set of base tags, which will be
included on every metric that gets emitted.base_tags=['mytag:myvalue']collector=DogstatsdCollector(dogstatsd,base_tags=base_tags)collector.histogram('query',tags=['database:master','verb:insert'])collector.histogram('query',tags=['database:master','verb:update'])collector.flush()# query:1|h|#database:master,verb:insert,mytag:myvalue# query:1|h|#database:master,verb:update,mytag:myvalueMotivationThe StatsD model is to run an agent on each server/container in your
infrastructure and periodically flush aggregations at a regular interval to a
centralized location. This model scales very well because the volume of metrics
sent to the centralized location grows very slowly even as you scale
your application; each StatsD agent calculates aggregations to flush to the
backend instead of every datapoint, so the storage volume is quite low even for
a large application with lots of volume.A drawback to this model is that you don’t have much control of the granularity
that your metrics represent. When your aggregations reach the centralized
location (DataDog in this case), you only know the counts or distributions
within the flush interval. You can’t represent any otherexecution
granularitybeyond “across X seconds” (where X is the flush interval). This
limitation precludes you from easily representings metrics on a “per-request”
basis, for example.The purpose of this library is to make it simple to control when your StatsD
metrics are emitted so that you can defer emission of the metrics until a point
you determine. This allows you to represent a finer granularity than “across X
seconds” such as “across a web request” or “across a cron job.” It also
preserves metric tags by emitting each series independently when the collector
is flushed, which ensures you don’t lose any of the benefit of tagging
your metrics (such as aggregating/slicing in DataDog).PatternsTheDogstatsdCollectorobject is a singleton that provides a similar
interface as theDogStatsDincrementandhistogrammethods. As you invoke these methods, you collect counters and histograms for
each series (determined by any tags you include). After callingflush(),
each series is separately emitted as a StatsD metric.Simple Request MetricsYou can collect various metrics over a request and emit them at the end of the
request to get per-request granularity.In Django:fromdatadog.dogstatsd.baseimportDogStatsdfromdogstatsd_collectorimportDogstatsdCollector# MiddlewareclassMetricsMiddleware:def__init__(self,get_response):self.get_response=get_responseself.dogstatsd=DogStatsd()def__call__(self,request):request.metrics=DogstatsdCollector(self.dogstatsd)response=self.get_response(request)request.metrics.flush()returnresponse# Inside a viewdefmy_view(request):# Do some stuff...request.metrics.increment('my.count')request.metrics.histogram('my.time',0.5)returnHttpResponse('ok')In Flask:fromdatadog.dogstatsd.baseimportDogStatsdfromdogstatsd_collectorimportDogstatsdCollectorfromflaskimportFlaskfromflaskimportrequestapp=Flask(__name__)dogstatsd=DogStatsd()@app.before_requestdefinit_metrics():request.metrics=DogstatsdCollector(dogstatsd)@app.after_requestdefflush_metrics():request.metrics.flush()@app.route('/')defmy_view():# Do some stuff...request.metrics.increment('my.count')request.metrics.histogram('my.time',0.5)return'ok'Celery Task MetricsSame as above, but over a Celery task.fromdatadog.dogstatsd.baseimportDogStatsdfromdogstatsd_collectorimportDogstatsdCollectorfromceleryimportCeleryfromceleryimportcurrent_taskfromcelery.signalsimporttask_prerunfromcelery.signalsimporttask_postrunapp=Celery('tasks',broker='pyamqp://guest@localhost//')dogstatsd=DogStatsd()@task_prerun.connectdefinit_metrics(task_id,task,*args,**kwargs):task.request.metrics=DogstatsdCollector(dogstatsd)@task_postrun.connectdefflush_metrics(task_id,task,*args,**kwargs):task.request.metrics.flush()@app.taskdefmy_task():# Do some stuff...current_task.request.metrics.increment('my.count')current_task.request.metrics.histogram('my.time',0.5)Metrics Within a FunctionEmit a set of metrics for a particular function you execute.fromdatadog.dogstatsd.baseimportDogStatsdfromdogstatsd_collectorimportDogstatsdCollectordogstatsd=DogStatsd()defdo_stuff(metrics):# Do some stuff...metrics.increment('my.count')metrics.histogram('my.time',0.5)metrics=DogstatsdCollector(dogstatsd)do_stuff(metrics)metrics.flush()Thread SafetyTheDogstatsdCollectorsingleton isnot threadsafe.Do not share a
singleDogstatsdCollectorobject among multiple threads.More DocumentationFull documentation can be found on ReadTheDocs:https://dogstatsd-collector.readthedocs.io/DevelopmentTo run the all tests run:toxChangelog0.0.2 (2019-08-14)Add base_tags optional kwarg to support tags added to all metrics that get
flushed.0.0.1 (2019-05-02)First release on PyPI.