From be6fc713f006001bf72dc47ada4c1f719c61784c Mon Sep 17 00:00:00 2001 From: zimengyang Date: Tue, 31 Jul 2018 16:37:27 -0700 Subject: [PATCH 1/5] initial commit --- README.md | 48 ++++++++++++++ example.py | 33 ++++++++++ setup.py | 36 ++++++++++ wavefront_dispatch/__init__.py | 65 +++++++++++++++++++ wavefront_dispatch/tests/__init__.py | 0 .../tests/test_wavefront_dispatch.py | 19 ++++++ 6 files changed, 201 insertions(+) create mode 100644 README.md create mode 100644 example.py create mode 100644 setup.py create mode 100644 wavefront_dispatch/__init__.py create mode 100644 wavefront_dispatch/tests/__init__.py create mode 100644 wavefront_dispatch/tests/test_wavefront_dispatch.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..963a550 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# wavefront_dispatch + +This package contains Wavefront python wrapper for Dispatch to send metrics directly to wavefront. + +## Requirements +Python 2.7 or 3.6 + +## Install +Install from PyPi +``` +pip install wavefront_dispatch +``` + +## Required Secrets + +* wavefront_sever_url = https://\.wavefront.com +* wavefront_auth_token = Wavefront API token with Direct Data Ingestion permission + +These secrets must be present in Dispatch functions' secrets of context. + +## Usage + +Decorate Dispatch handler function with @wavefront_dispatch.wrapper. + +```Python +import wavefront_dispatch + +@wavefront_dispatch.wrapper +def handler(ctx, payload): + # codes + +``` +And add `wavefront_dispatch` package as runtime dependency druing Dispatch python image creation. + +## Standard Metrics reported by Wavefront Dispatch wrapper + +Following metrics will be reported by wrapper: +|Metric Name |Type |Description | +|----------------------------------------|---------------|--------------------------------------------------| +|dispatch.function.wf.invocations.count |Delta Counter |Count of Dispatch function invocations | +|dispatch.function.wf.errors.count |Delta Counter |Count of Dispatch function executions with error | +|dispatch.function.wf.duration.value |Gauge |Execution time of Dispatch function in ms. | + + +## Custom Dispatch Function Metrics +Custom metrics powered by [pyformance plugin](https://github.com/wavefrontHQ/python-client/tree/master/wavefront_pyformance). + +Please refer to [example](https://github.com/dispatchframework/wavefront-dispatch-python/blob/master/example.py). \ No newline at end of file diff --git a/example.py b/example.py new file mode 100644 index 0000000..692c6b9 --- /dev/null +++ b/example.py @@ -0,0 +1,33 @@ +import wavefront_dispatch +import random + +@wavefront_dispatch.wrapper +def handle(ctx, payload): + + # Fibonacci + f_2, f_1 = 0, 1 + for n in range(random.randint(800, 900)): + f = f_1 + f_2 + f_2, f_1 = f_1, f + + # Customized metrics + registry = wavefront_dispatch.get_registry() + + # Report Gauge + gauge_val = registry.gauge("dispatch.function.wf.testgauge") + gauge_val.set_value(200) + + # Report Counter + counter = registry.counter("dispatch.function.wf.testcounter") + counter.inc() + + + +if __name__ == "__main__": + ctx = { + "secrets": { + "wavefront_server_url":"https://.wavefront.com", + "wavefront_auth_token":""} + } + payload = {} + handle(ctx, payload) \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..25c0eed --- /dev/null +++ b/setup.py @@ -0,0 +1,36 @@ +# coding: utf-8 + +""" + Wavefront Dispatch Wrapper + +

This is a Wavefront python wrapper for dispatch python function handler to send metrics directly to wavefront.

# noqa: E501 +""" + + +from setuptools import setup, find_packages # noqa: H301 + +NAME = "wavefront_dispatch" +VERSION = "0.0.1" +# To install the library, run the following +# +# python setup.py install +# +# prerequisite: setuptools +# http://pypi.python.org/pypi/setuptools + +REQUIRES = ["wavefront-pyformance >= 0.9.2"] + +setup( + name=NAME, + version=VERSION, + description="Wavefront Python Wrapper for Dispatch", + author_email="", + url="https://github.com/dispatchframework/wavefront-dispatch-python/tree/master", + keywords=["Wavefront Dispatch", "Wavefront"], + install_requires=REQUIRES, + packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), + include_package_data=True, + long_description="""\ + This is a Wavefront python wrapper for Dispatch function handler to send metrics directly to wavefront. + """ +) diff --git a/wavefront_dispatch/__init__.py b/wavefront_dispatch/__init__.py new file mode 100644 index 0000000..12d5ada --- /dev/null +++ b/wavefront_dispatch/__init__.py @@ -0,0 +1,65 @@ +from pyformance import MetricsRegistry +from wavefront_pyformance.wavefront_reporter import WavefrontDirectReporter +import os +from datetime import datetime +from wavefront_pyformance import delta + +reg = None + +def wrapper(func): + """ + Returns the Wavefront Dispatch wrapper. The wrapper collects dispatch functions + standard metrics and reports it directly to the specified wavefront url. It + requires the following Environment variables to be set: + 1.WAVEFRONT_URL : https://.wavefront.com + 2.WAVEFRONT_API_TOKEN : Wavefront API token with Direct Data Ingestion permission + """ + def call_dispatch_function(wf_reporter, *args, **kwargs): + + METRICS_PREFIX = "dispatch.function.wf." + # Register duration metrics + dispatch_function_duration_gauge = reg.gauge(METRICS_PREFIX + "duration") + # Register invocations metrics + dispatch_function_invocations_counter = delta.delta_counter(reg, METRICS_PREFIX + "invocations") + dispatch_function_invocations_counter.inc() + # Registry errors metrics + dispatch_erros_count = delta.delta_counter(reg, METRICS_PREFIX + "errors") + time_start = datetime.now() + try: + response = func(*args, **kwargs) + return response + except: + dispatch_erros_count.inc() + raise + finally: + time_taken = datetime.now() - time_start + dispatch_function_duration_gauge.set_value(time_taken.total_seconds() * 1000) + wf_reporter.report_now(registry=reg) + + def wavefront_wrapper(*args, **kwargs): + print("Func has been decorated.") + + # Initialize registry + global reg + reg = MetricsRegistry() + + # Get wavefront secrets + context, payload = args[0], args[1] + server = context["secrets"].get("wavefront_server_url", "") + auth_token = context["secrets"].get("wavefront_auth_token", "") + + # Initialize the wavefront direct reporter + wf_direct_reporter = WavefrontDirectReporter(server=server, + token=auth_token, + registry=reg, + prefix="") + + call_dispatch_function(wf_direct_reporter, + *args, + **kwargs) + + return wavefront_wrapper + + +def get_registry(): + return reg \ No newline at end of file diff --git a/wavefront_dispatch/tests/__init__.py b/wavefront_dispatch/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wavefront_dispatch/tests/test_wavefront_dispatch.py b/wavefront_dispatch/tests/test_wavefront_dispatch.py new file mode 100644 index 0000000..7465b47 --- /dev/null +++ b/wavefront_dispatch/tests/test_wavefront_dispatch.py @@ -0,0 +1,19 @@ +from unittest import TestCase +from wavefront_pyformance.wavefront_reporter import WavefrontDirectReporter +import unittest +from pyformance import MetricsRegistry +from wavefront_dispatch import wrapper + +@wrapper +def handler(ctx, payload): + return True + +class TestWrapper(TestCase): + def test_wavefront_wrapper(self): + #reg = MetricsRegistry() + function_wrapper = wrapper(handler) + assert(function_wrapper.__name__ == "wavefront_wrapper") + +if __name__ == '__main__': + # run 'python -m unittest discover' from toplevel to run tests + unittest.main() From 092c91eb7d7a875df23fac69d147ad8d0a9e3bcb Mon Sep 17 00:00:00 2001 From: zimengyang Date: Tue, 31 Jul 2018 17:02:09 -0700 Subject: [PATCH 2/5] tweak docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 963a550..a8919ac 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ pip install wavefront_dispatch ## Required Secrets -* wavefront_sever_url = https://\.wavefront.com +* wavefront_sever_url = https://.wavefront.com * wavefront_auth_token = Wavefront API token with Direct Data Ingestion permission These secrets must be present in Dispatch functions' secrets of context. From fafcd07dc07db64fb7d065c81773830bce06a12e Mon Sep 17 00:00:00 2001 From: zimengyang Date: Wed, 1 Aug 2018 15:06:15 -0700 Subject: [PATCH 3/5] Add PyPi project link --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a8919ac..9256b04 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Install from PyPi ``` pip install wavefront_dispatch ``` +More package [details](https://pypi.org/project/wavefront-dispatch/) on PyPi. ## Required Secrets From 7d5b519ebe28e6ba7d139f90d35c6f71eb066fd0 Mon Sep 17 00:00:00 2001 From: zimengyang Date: Wed, 1 Aug 2018 16:05:22 -0700 Subject: [PATCH 4/5] tweak docs and bump 0.0.2 --- README.md | 25 +++++++++++++++++++++++-- setup.py | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9256b04..99fb96a 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Decorate Dispatch handler function with @wavefront_dispatch.wrapper. import wavefront_dispatch @wavefront_dispatch.wrapper -def handler(ctx, payload): +def handle(ctx, payload): # codes ``` @@ -46,4 +46,25 @@ Following metrics will be reported by wrapper: ## Custom Dispatch Function Metrics Custom metrics powered by [pyformance plugin](https://github.com/wavefrontHQ/python-client/tree/master/wavefront_pyformance). -Please refer to [example](https://github.com/dispatchframework/wavefront-dispatch-python/blob/master/example.py). \ No newline at end of file +Please refer to following [example](https://github.com/dispatchframework/wavefront-dispatch-python/blob/master/example.py): + +```Python +import wavefront_dispatch +import random + +@wavefront_dispatch.wrapper +def handle(ctx, payload): + + # Customized metrics + registry = wavefront_dispatch.get_registry() + + # Report Gauge + gauge_val = registry.gauge("dispatch.function.wf.testgauge") + gauge_val.set_value(200) + + # Report Counter + counter = registry.counter("dispatch.function.wf.testcounter") + counter.inc() + + ... +``` \ No newline at end of file diff --git a/setup.py b/setup.py index 25c0eed..7ede399 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ from setuptools import setup, find_packages # noqa: H301 NAME = "wavefront_dispatch" -VERSION = "0.0.1" +VERSION = "0.0.2" # To install the library, run the following # # python setup.py install From e832d62143e17c703c4cf64dcf1c9923d6887395 Mon Sep 17 00:00:00 2001 From: zimengyang Date: Thu, 2 Aug 2018 10:42:47 -0700 Subject: [PATCH 5/5] tweak doc --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 99fb96a..603924a 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ And add `wavefront_dispatch` package as runtime dependency druing Dispatch pytho ## Standard Metrics reported by Wavefront Dispatch wrapper Following metrics will be reported by wrapper: -|Metric Name |Type |Description | -|----------------------------------------|---------------|--------------------------------------------------| -|dispatch.function.wf.invocations.count |Delta Counter |Count of Dispatch function invocations | -|dispatch.function.wf.errors.count |Delta Counter |Count of Dispatch function executions with error | -|dispatch.function.wf.duration.value |Gauge |Execution time of Dispatch function in ms. | +| Metric Name | Type | Description | +|---|---|---| +| dispatch.function.wf.invocations.count | Delta Counter | Count of Dispatch function invocations. | +| dispatch.function.wf.errors.count | Delta Counter | Count of Dispatch function executions with error. | +| dispatch.function.wf.duration.value | Gauge | Execution time of Dispatch function in ms. | ## Custom Dispatch Function Metrics