# Statsdecor
[![PyPI](https://img.shields.io/pypi/v/statsdecor)](https://pypi.org/project/statsdecor/)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/statsdecor)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.txt)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/amcintosh/statsdecor/run-tests.yml?branch=main)](https://github.com/amcintosh/statsdecor/actions?query=workflow%3A%22Run+Tests%22)
A set of decorators and helper methods for adding statsd metrics to applications.
## Installation
You can use pip to install statsdecor:
```shell
pip install statsdecor
```
## Configuration
You must use `statsdecor.configure` to configure the internal statsd client before
calling other methods:
```python
import statsdecor
statsdecor.configure(host='localhost', prefix='superapp.')
```
Configuration is generally setup during your application's bootstrap. Once
set configuration values are re-used in all clients that `statsdecor` creates.
By default Statsdecor uses the [statsd](https://pypi.org/project/statsd/) client library,
however it can be configured to use the [datadog](https://pypi.org/project/datadog/) client:
```python
import statsdecor
statsdecor.configure(host='localhost', prefix='superapp.', vendor='datadog')
```
The datadog client supports [tagging metrics](https://statsd.readthedocs.io/en/stable/tags.html) (see Usage).
## Usage
You can track metrics with either the module functions, or decorators. Incrementing
and decrementing counters looks like:
### Metric functions
```python
import statsdecor
statsdecor.incr('save.succeeded')
statsdecor.decr('attempts.remaining')
statsdecor.gauge('sessions.active', 9001)
```
When using the datadog client, Statsdecor supports tagging metrics:
```python
statsdecor.incr('save.succeeded', tags=['DogStatsd_does_tags'])
```
Counters and timers can also be set through decorators:
```python
import statsdecor.decorators as stats
@stats.increment('save.succeeded')
def save(self):
pass
@stats.decrement('attempts.remaining')
def attempt():
pass
@stats.timed('api_request.duration')
def perform_request(self, req)
pass
```
When using decorators, metrics are only tracked if the decorated function
does not raise an error.
### Context
When using a [statsd client that supports tagging metrics](https://statsd.readthedocs.io/en/stable/tags.html),
Statsdecor includes a context manager that can help measure latency and volume while using metric tags to
classify their success & failure. For example, suppose you are making a call to a remote service and wish
to write a wrapper that collects latency, volume and failure metrics.
With our knowledge about how the client library indicates errors we can make a context manager
based on StatsContext:
```python
from statsdecor.context import StatsContext
class FoobarClientMetrics(StatsContext):
def __init__(self, tags=None):
tags = list(tags or [])
tags += ['caller:example_1']
super(ThingyStatsContext, self).__self__('thingy_client', tags=tags)
def exit_hook(self, exc_type, exc_val, exc_tb):
if exc_val is not None:
self.add_tags('result:failure')
else:
self.add_tags('result:success')
# Bonus: since we have the exception, classify the error type
if isinstance(exc_val, PermissionDenied):
self.add_tags('error:permissiondenied')
elif isinstance(exc_val, TimeOut):
self.add_tags('error:timeout')
elif exc_val is not None:
self.add_tags('error:exception')
```
Now writing wrapper functions with metrics is simple:
```python
def foobar_get_clients(**args):
with FoobarClientMetrics(tags=['method:get_clients']) as stats:
result = call_foobar_get_client(**args)
# We know all foo methods return result['status_code'] so let's
# add a status_code tag!
stats.add_tags('status_code:{}'.format(result["status_code"]'))
return result
def foobar_add_client(**args):
with FoobarClientMetrics(tags=['method:add_client']) as stats:
result = call_foobar_add_client(**args)
stats.add_tags('status_code:{}'.format(result["status_code"]'))
return result
```
Now we can graph:
* volume of calls grouped by the `method` tag
* average response time, excluding errors (timeouts will no longer skew the average)
* volume of errors grouped by method, and/or type
## Development
### Testing
```shell
make lint
make test
```
### Releasing
statsdecor uses [semver](https://semver.org) for version numbers. Before tagging,
check for all changes since the last tag for breaking changes, new features,
and/or bugfixes.
To tag the new version:
```shell
make tag VERSION_PART=major|minor|patch
```
Proceed to github.com/amcintosh/statsdecor/releases and create a new release with the tag.
Github actions should publish to pypi automatically.
Raw data
{
"_id": null,
"home_page": "https://github.com/amcintosh/statsdecor",
"name": "statsdecor",
"maintainer": "Andrew McIntosh",
"docs_url": null,
"requires_python": null,
"maintainer_email": "andrew@amcintosh.net",
"keywords": "statsd, stats",
"author": "Freshbooks Dev Team",
"author_email": "opensource@freshbooks.com",
"download_url": "https://files.pythonhosted.org/packages/72/be/966deefb39834d8be2879f570a743c1d81ef7fe7bd0ab7dcdc5d6e614bcf/statsdecor-0.4.2.tar.gz",
"platform": null,
"description": "# Statsdecor\n\n[![PyPI](https://img.shields.io/pypi/v/statsdecor)](https://pypi.org/project/statsdecor/)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/statsdecor)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.txt)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/amcintosh/statsdecor/run-tests.yml?branch=main)](https://github.com/amcintosh/statsdecor/actions?query=workflow%3A%22Run+Tests%22)\n\nA set of decorators and helper methods for adding statsd metrics to applications.\n\n## Installation\n\nYou can use pip to install statsdecor:\n\n```shell\npip install statsdecor\n```\n\n## Configuration\n\nYou must use `statsdecor.configure` to configure the internal statsd client before\ncalling other methods:\n\n```python\nimport statsdecor\n\nstatsdecor.configure(host='localhost', prefix='superapp.')\n```\n\nConfiguration is generally setup during your application's bootstrap. Once\nset configuration values are re-used in all clients that `statsdecor` creates.\n\nBy default Statsdecor uses the [statsd](https://pypi.org/project/statsd/) client library,\nhowever it can be configured to use the [datadog](https://pypi.org/project/datadog/) client:\n\n```python\nimport statsdecor\n\nstatsdecor.configure(host='localhost', prefix='superapp.', vendor='datadog')\n```\n\nThe datadog client supports [tagging metrics](https://statsd.readthedocs.io/en/stable/tags.html) (see Usage).\n\n## Usage\n\nYou can track metrics with either the module functions, or decorators. Incrementing\nand decrementing counters looks like:\n\n### Metric functions\n\n```python\nimport statsdecor\n\nstatsdecor.incr('save.succeeded')\nstatsdecor.decr('attempts.remaining')\nstatsdecor.gauge('sessions.active', 9001)\n```\n\nWhen using the datadog client, Statsdecor supports tagging metrics:\n\n```python\nstatsdecor.incr('save.succeeded', tags=['DogStatsd_does_tags'])\n```\n\nCounters and timers can also be set through decorators:\n\n```python\nimport statsdecor.decorators as stats\n\n@stats.increment('save.succeeded')\ndef save(self):\n pass\n\n@stats.decrement('attempts.remaining')\ndef attempt():\n pass\n\n@stats.timed('api_request.duration')\ndef perform_request(self, req)\n pass\n```\n\nWhen using decorators, metrics are only tracked if the decorated function\ndoes not raise an error.\n\n### Context\n\nWhen using a [statsd client that supports tagging metrics](https://statsd.readthedocs.io/en/stable/tags.html),\nStatsdecor includes a context manager that can help measure latency and volume while using metric tags to\nclassify their success & failure. For example, suppose you are making a call to a remote service and wish\nto write a wrapper that collects latency, volume and failure metrics.\n\nWith our knowledge about how the client library indicates errors we can make a context manager\nbased on StatsContext:\n\n```python\nfrom statsdecor.context import StatsContext\n\nclass FoobarClientMetrics(StatsContext):\n def __init__(self, tags=None):\n tags = list(tags or [])\n tags += ['caller:example_1']\n super(ThingyStatsContext, self).__self__('thingy_client', tags=tags)\n\n def exit_hook(self, exc_type, exc_val, exc_tb):\n if exc_val is not None:\n self.add_tags('result:failure')\n else:\n self.add_tags('result:success')\n\n # Bonus: since we have the exception, classify the error type\n if isinstance(exc_val, PermissionDenied):\n self.add_tags('error:permissiondenied')\n elif isinstance(exc_val, TimeOut):\n self.add_tags('error:timeout')\n elif exc_val is not None:\n self.add_tags('error:exception')\n\n```\n\nNow writing wrapper functions with metrics is simple:\n\n```python\ndef foobar_get_clients(**args):\n with FoobarClientMetrics(tags=['method:get_clients']) as stats:\n result = call_foobar_get_client(**args)\n\n # We know all foo methods return result['status_code'] so let's\n # add a status_code tag!\n stats.add_tags('status_code:{}'.format(result[\"status_code\"]'))\n return result\n\ndef foobar_add_client(**args):\n with FoobarClientMetrics(tags=['method:add_client']) as stats:\n result = call_foobar_add_client(**args)\n stats.add_tags('status_code:{}'.format(result[\"status_code\"]'))\n return result\n```\n\nNow we can graph:\n\n* volume of calls grouped by the `method` tag\n* average response time, excluding errors (timeouts will no longer skew the average)\n* volume of errors grouped by method, and/or type\n\n## Development\n\n### Testing\n\n```shell\nmake lint\nmake test\n```\n\n### Releasing\n\nstatsdecor uses [semver](https://semver.org) for version numbers. Before tagging,\ncheck for all changes since the last tag for breaking changes, new features,\nand/or bugfixes.\n\nTo tag the new version:\n\n```shell\nmake tag VERSION_PART=major|minor|patch\n```\n\nProceed to github.com/amcintosh/statsdecor/releases and create a new release with the tag.\nGithub actions should publish to pypi automatically.\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A set of decorators and helper methods for adding statsd metrics to applications.",
"version": "0.4.2",
"project_urls": {
"Homepage": "https://github.com/amcintosh/statsdecor"
},
"split_keywords": [
"statsd",
" stats"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "dd9081e0a8baca8ea91189b839c8b2d922a9894ee2977c80e135ad0a60f4be4b",
"md5": "c8d110cee49fbc5538e9c67419371edf",
"sha256": "980cf77dbda83c97556f7a33b37f0eb7eb94c1f83bc815b099adc411115baa0d"
},
"downloads": -1,
"filename": "statsdecor-0.4.2-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "c8d110cee49fbc5538e9c67419371edf",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 7815,
"upload_time": "2024-12-10T17:09:35",
"upload_time_iso_8601": "2024-12-10T17:09:35.336062Z",
"url": "https://files.pythonhosted.org/packages/dd/90/81e0a8baca8ea91189b839c8b2d922a9894ee2977c80e135ad0a60f4be4b/statsdecor-0.4.2-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "72be966deefb39834d8be2879f570a743c1d81ef7fe7bd0ab7dcdc5d6e614bcf",
"md5": "90493b29b12bd6b1c3babbd784d761a6",
"sha256": "44aa6294793124c798f0c1ff572a1aeafef687b8fa148a5f2dde93086934be9d"
},
"downloads": -1,
"filename": "statsdecor-0.4.2.tar.gz",
"has_sig": false,
"md5_digest": "90493b29b12bd6b1c3babbd784d761a6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11829,
"upload_time": "2024-12-10T17:09:36",
"upload_time_iso_8601": "2024-12-10T17:09:36.309855Z",
"url": "https://files.pythonhosted.org/packages/72/be/966deefb39834d8be2879f570a743c1d81ef7fe7bd0ab7dcdc5d6e614bcf/statsdecor-0.4.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-10 17:09:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "amcintosh",
"github_project": "statsdecor",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "statsd",
"specs": []
},
{
"name": "datadog",
"specs": []
}
],
"lcname": "statsdecor"
}