Another quick blog post today to show-case usage of riemann for in-app reporting. This small blurb will push out a metric for each wrap route with the metric name you provide.
When handlers raise exceptions, a metric is sent out as well with the exception's message as description.
import socket import time import bernhard # [...] def wrap_riemann(metric, client=bernhard.Client(), tags=['python']): def riemann_decorator(f): @wraps(f) def decorated_function(*args, **kwargs): host = socket.gethostname() started = time.time() try: response = f(*args, **kwargs) except Exception as e: client.send({'host': host, 'service': metric + "-exceptions", 'description': str(e), 'tags': tags + ['exception'], 'state': 'critical', 'metric': 1}) raise duration = (time.time() - started) * 1000 clientsend({'host': host, 'service': metric + "-time", 'tags': tags + ['duration'], 'metric': duration}) return response return decorated_function return riemann_decorator
Provided you have a flask app for instance you could then have use the wrapper in the following way:
app = Flask(__name__) riemann = bernhard.Client() @app.route('/users') @wrap_riemann('list-users', client=riemann) def list_users(): # [...] @app.route('/users/<id>', methods=['DELETE']) @wrap_riemann('delete-user', client=riemann) def delete_users(): # [...]
In riemann we can easily massage these events to give us points worth looking at:
;; start-up servers (tcp-server :host "0.0.0.0") (udp-server :host "0.0.0.0") (def graph (graphite {:host "your.graphite.host"})) (def index (default {:state "ok" :ttl 60} (update-index (index)))) (periodically-expire 5 index) (streams ;; we're interested in events coming from the python web app (tagged "python" ;; aggregate duration event for each interval of one second ;; then compute the mean before sending of to indexer and grapher (tagged "duration" ;; We split by service to get one metric per route (by [:service] (fixed-time-window 1 (combine folds/mean index graph))) ;; unsplitted, we'll get an overall metric (with {:service "overall-mean-duration"} (fixed-time-window 1 (combine folds/mean index graph)))) ;; sum exceptions per second (tagged "exception" (by [:service] (rate 1 index graph)) (with {:service "overall-exceptions"} (rate 1 index graph)))))
Obviously this wrapper would work just as well for any python function. As a ways
I extended a bit on this idea and released a cleaned up version here: https://github.com/exoscale/python-riemann-wrapper.