diff --git a/README.md b/README.md index 55f9535..f939953 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ The Tilt supports writing to a google doc which you could use with something lik * Webhooks * InfluxDB +* Datadog (dogstatsd) ## Usage ## @@ -40,6 +41,11 @@ port = 80 database = tilty gravity_payload_template = {"measurement": "gravity", "tags": {"color": "{{ color }}"}, "fields": {"value": {{ gravity }}}} temperature_payload_template = {"measurement": "temperature", "tags": {"color": "{{ color }}"}, "fields": {"value": {{ temp }}}} + +[datadog] +# Note: make sure that the dd agent has DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true +host = statsdhost.corp.com +port = 8125 EOF ``` diff --git a/poetry.lock b/poetry.lock index 51f9044..1953f59 100644 --- a/poetry.lock +++ b/poetry.lock @@ -82,6 +82,26 @@ version = "5.0" [package.extras] toml = ["toml"] +[[package]] +category = "main" +description = "The Datadog Python library" +name = "datadog" +optional = false +python-versions = "*" +version = "0.34.1" + +[package.dependencies] +decorator = ">=3.3.2" +requests = ">=2.6.0" + +[[package]] +category = "main" +description = "Decorators for Humans" +name = "decorator" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "4.4.1" + [[package]] category = "dev" description = "Discover and load entry points from installed packages." @@ -484,7 +504,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["pathlib2", "contextlib2", "unittest2"] [metadata] -content-hash = "aaaaaee62ecd567cb981bd6029700fd8189fc7da649f363cbd32793f686a74ad" +content-hash = "63700482ba8be79d7168685bb69b9e9e9f24efd6ef6537cd82112eec37c5849b" python-versions = ">=3.6,<3.8" [metadata.files] @@ -549,6 +569,14 @@ coverage = [ {file = "coverage-5.0-cp39-cp39m-win_amd64.whl", hash = "sha256:c1b030a79749aa8d1f1486885040114ee56933b15ccfc90049ba266e4aa2139f"}, {file = "coverage-5.0.tar.gz", hash = "sha256:e1bad043c12fb58e8c7d92b3d7f2f49977dcb80a08a6d1e7a5114a11bf819fca"}, ] +datadog = [ + {file = "datadog-0.34.1-py2.py3-none-any.whl", hash = "sha256:186b25a51e160e4d6ee599c647d83dca60d6889f852e07e552fdad18b0d0b6f5"}, + {file = "datadog-0.34.1.tar.gz", hash = "sha256:3bd8cc3d6915c6ac74c68093068b903de3fae22b8dd3d31480bfc2092a1f51d7"}, +] +decorator = [ + {file = "decorator-4.4.1-py2.py3-none-any.whl", hash = "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"}, + {file = "decorator-4.4.1.tar.gz", hash = "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce"}, +] entrypoints = [ {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, diff --git a/pyproject.toml b/pyproject.toml index c35a39a..ce35669 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "Tilty" -version = "0.0.1" +version = "0.3.0" description = "A pluggable system to receive and transmit bluetooth events from the Tilt Hydrometer" authors = ["Marcus Young <3vilpenguin@gmail.com>"] license = "MIT" @@ -12,6 +12,7 @@ pybluez = "^0.22.0" requests = "^2.22" jinja2 = "^2.11.1" influxdb = "^5.2.3" +datadog = "^0.34.1" [tool.poetry.dev-dependencies] flake8 = "^3.7" diff --git a/requirements.txt b/requirements.txt index 959afef..0d37b0c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,8 @@ certifi==2019.11.28 chardet==3.0.4 Click==7.0 coverage==5.0 +datadog==0.34.1 +decorator==4.4.1 entrypoints==0.3 filelock==3.0.12 flake8==3.7.9 diff --git a/setup.py b/setup.py index ba852a6..081f6ae 100644 --- a/setup.py +++ b/setup.py @@ -13,10 +13,11 @@ long_description=long_description, long_description_content_type="text/markdown", py_modules=['tilty', 'blescan'], - version='0.2.2', + version='0.3.0', packages=find_packages(exclude=['tests*']), install_requires=[ 'Click', + 'datadog', 'influxdb', 'Jinja2', 'pybluez', diff --git a/tests/mock_config_parser.py b/tests/mock_config_parser.py index 9d6ba78..608226c 100644 --- a/tests/mock_config_parser.py +++ b/tests/mock_config_parser.py @@ -18,6 +18,11 @@ def __getitem__(self, key): 'gravity_payload_template': 'gravity,color={{ color }} value={{ gravity }} {{timestamp}}', # noqa 'temperature_payload_template': 'temperature,scale=fahrenheit,color={{ color }} value={{ temp }} {{timestamp}}', # noqa } + if self.section == 'datadog': + return { + 'host': 'http://api.datadog.com', + 'port': '8120', + } return None def has_section(self, *args, **kwargs): diff --git a/tests/test_datadog.py b/tests/test_datadog.py new file mode 100644 index 0000000..2aab82a --- /dev/null +++ b/tests/test_datadog.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from unittest import mock + +from tilty.emitters import datadog + + +@mock.patch('tilty.emitters.datadog.statsd') +@mock.patch('tilty.emitters.datadog.initialize') +def test_datadog( + mock_statsd_init, + mock_statsd_client, +): + config = { + 'host': 'http://statsd.google.com', + 'port': '8130', + 'temperature': '55', + 'gravity': '1054', + 'color': 'black', + } + datadog.Datadog(config=config).emit() + mock_statsd_init.mock_calls == [ + mock.call(statsd_host='http://statsd.google.com', statsd_port='8130') + ] + assert mock_statsd_client.mock_calls == [ + mock.call.gauge('tilty.temperature', '55', tags=['color:black']), + mock.call.gauge('tilty.gravity', '1054', tags=['color:black']), + ] diff --git a/tests/test_tilty.py b/tests/test_tilty.py index ec100c5..eb286a8 100644 --- a/tests/test_tilty.py +++ b/tests/test_tilty.py @@ -56,3 +56,18 @@ def test_scan_for_tilt_data_parse_influxdb( ), mock.call().emit() ] + + +@mock.patch('tilty.emitters.datadog.Datadog') +def test_scan_for_tilt_data_parse_datadog( + mock_dd, +): + config = MockConfigParser('datadog') + tilty.emit( + config, + {'color': 'black', 'gravity': 1, 'temp': 32, 'timestamp': 155558888} + ) + assert mock_dd.mock_calls == [ + mock.call(config={'host': 'http://api.datadog.com', 'port': '8120', 'gravity': 1, 'temperature': 32, 'color': 'black'}), # noqa + mock.call().emit() + ] diff --git a/tilty/emitters/datadog.py b/tilty/emitters/datadog.py new file mode 100644 index 0000000..556d63f --- /dev/null +++ b/tilty/emitters/datadog.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +""" DataDog emitter """ +import logging + +from datadog import initialize, statsd + +from tilty.common import safe_get_key + +LOGGER = logging.getLogger() + + +class Datadog: # pylint: disable=too-few-public-methods + """ Class to represent the actual device """ + def __init__(self, config): + """ Initializer + + Args: + config: (dict) represents the configuration for the emitter + """ + self.temperature = config['temperature'] + self.gravity = config['gravity'] + self.color = config['color'] + options = { + 'statsd_host': config['host'], + 'statsd_port': safe_get_key(config, 'port', 8125), + } + initialize(**options) + + def emit(self, **kwargs): # pylint: disable=no-self-use,unused-argument + """ Initializer + + Args: + """ + LOGGER.info('[datadog] posting temperature data') + statsd.gauge( + 'tilty.temperature', + self.temperature, + tags=[f"color:{self.color}"] + ) + LOGGER.info('[datadog] posting gravity data') + statsd.gauge( + 'tilty.gravity', + self.gravity, + tags=[f"color:{self.color}"] + ) diff --git a/tilty/tilty.py b/tilty/tilty.py index c7dd67a..f228b1e 100644 --- a/tilty/tilty.py +++ b/tilty/tilty.py @@ -4,7 +4,7 @@ from jinja2 import Template -from tilty.emitters import influxdb, webhook +from tilty.emitters import datadog, influxdb, webhook def emit(config, tilt_data): @@ -65,3 +65,18 @@ def emit(config, tilt_data): } _influxdb = influxdb.InfluxDB(config=_config) _influxdb.emit() + + # + # [datadog] + # host = 'host' + # port = 'port' + if config.has_section('datadog'): + _config = { + 'host': config['datadog']['host'], + 'port': config['datadog']['port'], + 'gravity': tilt_data['gravity'], + 'temperature': tilt_data['temp'], + 'color': tilt_data['color'], + } + _datadog = datadog.Datadog(config=_config) + _datadog.emit()