-
Notifications
You must be signed in to change notification settings - Fork 1
Initial commit for wavefront wrapper for dispatch #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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://<INSTANCE>.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() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're getting an instance of registry every time a function gets invoked. Is that intentional (recommended / required)? If not, it better be initialized once and reused.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The registry is MetricsRegistry which only contains various maps of metrics types. My understanding is that the registry is for keeping track of current metrics during execution and should not be expensive. It has to be created every time for new function invocation. |
||
|
|
||
| # 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() | ||
|
|
||
| ... | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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://<INSTANCE>.wavefront.com", | ||
| "wavefront_auth_token":"<AUTH_TOKEN>"} | ||
| } | ||
| payload = {} | ||
| handle(ctx, payload) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # coding: utf-8 | ||
|
|
||
| """ | ||
| Wavefront Dispatch Wrapper | ||
|
|
||
| <p>This is a Wavefront python wrapper for dispatch python function handler to send metrics directly to wavefront.</p> # 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. | ||
| """ | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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://<INSTANCE>.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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The table looks screwed up, like this:
Following metrics will be reported by wrapper:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did insert extract spaces and dashes for alignments with table header and contents. I will delete those extra spaces since the final rendering markdown are the same.