diff --git a/README.md b/README.md new file mode 100644 index 0000000..603924a --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# 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 +``` +More package [details](https://pypi.org/project/wavefront-dispatch/) on PyPi. + +## 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 handle(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 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/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..7ede399 --- /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.2" +# 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()