PK„zþN½-™º°°red/__init__.py"""RED Metrics tracker able to instrument flask views using prometheus metrics.""" from red.blueprint import metrics_blueprint from red.metrics import HTTP_EXCEPTIONS_TOTAL, HTTP_REQUESTS_LATENCY, HTTP_REQUESTS_TOTAL from red.tracker import REDMetricsTracker __all__ = [ "REDMetricsTracker", "metrics_blueprint", "HTTP_REQUESTS_TOTAL", "HTTP_EXCEPTIONS_TOTAL", "HTTP_REQUESTS_LATENCY", ] __version__ = "0.1.1" PKrzþN\©Xϲ²red/blueprint.py"""Flask Blueprint for implementing prometheus metrics exposition via `GET /metrics`.""" from flask import Blueprint, Response from prometheus_client import CONTENT_TYPE_LATEST, generate_latest #: A blueprint implementing a /metrics endpoint. metrics_blueprint = Blueprint("prometheus_metrics", __name__) @metrics_blueprint.route("/metrics") def expose_metrics(): return Response(generate_latest, mimetype=CONTENT_TYPE_LATEST) PKO[öNŸ=7½½red/metrics.py"""Prometheus Metrics used to monitor URL views. Available metrics are: http_requests_total The total number of requests made to the application. http_exceptions_total The total number of exceptions raised during processing or requests. Please note that *404 Not Found* errors caused by requesting incorrect URLs are **NOT** included in this metric, since they are raised during routing, before the execution of any of our endpoint functions. However, `404 Not Found` exceptions raised explicitly by our functions are monitored. http_requests_latency_seconds The number of seconds required to process requests to endpoints of the application. All of the above metrics offer `path` and `method` labels for more granular filtering using PromQL. """ from prometheus_client import Counter, Histogram #: Counter Metric, counting all requests made and processed by a decorated view. This #: is regardless of whether or not there was an exception during the request of that view. HTTP_REQUESTS_TOTAL = Counter( "http_requests_total", "Total amount of HTTP Requests made.", labelnames=["method", "path"] ) #: Tracks if an exception occurred during the execution of the decorated view. Note that any #: `404 Not Found` errors which happen during routing are NOT part of this metric, as the corresponding #: exceptions happens during routing, and not in this view. Any `404 Not Found` exceptions #: raised explicitly in the view are still counted towards this metric. HTTP_EXCEPTIONS_TOTAL = Counter( "http_exceptions_total", "Total amount of HTTP exceptions.", labelnames=["method", "path"] ) #: Tracks the amount of time it took in seconds, to process the request in the view. This #: includes requests that resulted in an exception. HTTP_REQUESTS_LATENCY = Histogram( "http_requests_latency_seconds", "Duration of HTTP requests processing.", labelnames=["method", "path"], ) PKò¶öN›ê•ççred/tracker.py"""REDMetricsTracker with :mod:`flask` support. Tracking all methods and exceptions for all requests on a view:: app = flask.Flask(__name__) @app.route("/endpoint") @FlaskRedMetricsTracker.track() def do_things(): ... return "OK" Limiting metrics tracking to specific methods:: @app.route("/endpoint", methods=["POST", "GET", "PUT", "DELETE"]) @FlaskRedMetricsTracker.track(methods=["POST", "DELETE"]) def do_things(): ... return "OK" Limiting to specific exceptions:: @app.route("/endpoint/") @FlaskRedMetricsTracker.track(exceptions=MySpecialException) def do_things(): ... if condition == "throw": raise MySpecialException return "OK" """ import timeit from functools import wraps from typing import Optional, Union, Tuple, List, Type, Iterable from flask import request from red.metrics import HTTP_EXCEPTIONS_TOTAL, HTTP_REQUESTS_TOTAL, HTTP_REQUESTS_LATENCY class REDMetricsTracker: """REDMetricsTracker class for :mod:`flask` applications. Dynamically looks up method and path of the request currently handled by the decorated view. Allows limiting collected metrics to certain HTTP methods, as well as specific exceptions. :param method: HTTP Method(s) to track metrics for. Defaults to all. :param exc: Exception(s) to track metrics for. Defaults to all exceptions raised in the view. """ def __init__( self, methods: Optional[Union[str, Iterable[str]]] = None, exceptions: Optional[Union[Tuple[Type[Exception], ...], Type[Exception]]] = None, ): self.methods = methods if methods is not None: self.methods = [methods] if isinstance(methods, str) else methods self.exc = exceptions self.start = None self.last_response = None def __enter__(self): self.start = None if self.trackable_request: self.start = timeit.default_timer() self.total_requests.inc() return self def __exit__(self, exc_type, exc_val, exc_tb): """Track latency and exceptions, if any. Latency and exceptions are tracked if :attr:`request.method` is present in :attr:`.methods`. In flask, exceptions may occur in two ways: * Exceptions raised from user code in the view function (resulting in a 500 down stream). * :class:`werkzeug.exceptions.HTTPExceptions` returned by the view function. """ if self.trackable_request: # Track the latency (request duration) of the request, in seconds. duration = max(timeit.default_timer() - self.start, 0) self.latency.observe(duration) # Fetch any exception that may have occurred. if exc_type: # User code raised an unhandled error (aka. 500 Internal Server Error downstream). exception = exc_type elif self.last_response: # The view function returned an HTTPException response. exception = self.last_response if self.trackable_exception(exception): self.total_exceptions.inc() return exc_type, exc_val, exc_tb @property def trackable_request(self) -> bool: """Check if the request's HTTP Verb is in the tracked methods list.""" if self.methods is None: # Track all requests made to this view. return True # Only track a specific set of methods return request.method in self.methods def trackable_exception(self, exception: Type[Exception]) -> bool: """Check if the given `exception` is meant to be tracked. Returns a :class:`bool` indicating whether or not we should track the exception. """ if self.exc is None: # No filter specified, track all exceptions return True elif isinstance(self.exc, Iterable): # We have an iterable of exceptions to filter for return exception in self.exc # We should only filter for one exception type return exception == self.exc @property def labels(self): """Loads the method, path for the current view and request. This accesses flask's :attr:`flask.request` thread-local variable, if no `method` or `path` were sent during instantiation of this instance. """ return {"method": request.method, "path": request.path} @property def total_requests(self): """Convenience property to allow easier access to the underlying counter metric. Returns the metric for the configured :attr:`.labels` from :attr:`.HTTP_TOTAL_REQUESTS`. """ return HTTP_REQUESTS_TOTAL.labels(**self.labels) @property def total_exceptions(self): """Convenience property to allow easier access to the underlying counter metric. Returns the metric for the configured :attr:`.labels` from :attr:`.HTTP_TOTAL_EXCEPTIONS`. """ return HTTP_EXCEPTIONS_TOTAL.labels(**self.labels) @property def latency(self): """Convenience property to allow easier access to the underlying counter metric. Returns the metric for the configured :attr:`.labels` from :attr:`.HTTP_REQUEST_LATENCY`. """ return HTTP_REQUESTS_LATENCY.labels(**self.labels) @classmethod def track( cls, method: Optional[Union[List[str], str]] = None, exc: Optional[Union[Tuple[Type[Exception], ...], Type[Exception]]] = None, ): """Track RED Metrics for a view. URL views decorated with this method will track total requests, latency and occurred exceptions. By default all HTTP Methods and exceptions are tracked. It is possible to limit this by passing a str or list of strings in the `method` parameter, to limit the tracked HTTP Verbs to the given list. Likewise, the exceptions tracked can be limited by passing an exception class or tuple of several exception classes to the `exc` parameter. """ def instrument_view(view_func): @wraps(view_func) def instrumented_view(*args, **kwargs): with cls(methods=method, exceptions=exc) as tracker: resp = view_func(*args, **kwargs) tracker.last_response = resp return resp return instrumented_view return instrument_view PK†AôN‡ç¢—00+RED_Metrics_Tracker-0.1.1.dist-info/LICENSEMIT License Copyright (c) 2019 Nils Diefenbach Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HÎÂôPO)RED_Metrics_Tracker-0.1.1.dist-info/WHEEL ÏHMÍÑ K-*ÎÌϳR0Ô3àrOÍK-J,É/²RHËÉ,Šsåç—èz딥æd&Y)”•¦r…$¦[)Tëæåç¥ê&æUrPK!H¥7¸Ó1 ,RED_Metrics_Tracker-0.1.1.dist-info/METADATAÍVÛrÛ6}ÇWìè%öŒHÙU“¸l™‰ɉÆ×±åæ¡“‘@r)¡& Ùúû.x±äH‰ì¶åƒe.Î^Î.pÀs4<á†{ ÒBüä² žc×ÃwŽF‰X{cÅã;TìvàðÆæ9WË LeF‚(´Q6ÇÂ@šq} ÷¬Å J%s4s´òÚßgŸÈä•|F5Ì)uÐëÍ„™ÛÈeÞ+2¤EÏ{Û <1šñk:çЗ7#8.©E Cïç£q»üÄåJÉ™âyîyÆ‹™¥™9|MÖýׯÂÙò…~£¼Ìðq"Îò¡^\ut ´ Öæ8‰3¢k¾T[î[c”Ñn ÃÃ_ü~tð+PÓ‡0„N‚‹Î–wxäEv!WäuäùÏõ2–ˆ„áOçªÿ<Ÿ0ìûoý×»ÀBKeÂðg¿ï¾Ù.—u…~½»ô¼ŽrïFcû cãÝ^Ÿð»Asèº/>¦=¡µEý4âGa>ÙèåÁ\”…H¨ü¡+8â´as Ûæn>ìF¸ý÷ߪc#ráYÖfdì31„i)Êid ±´Š¤+` è!s•„<Ö¥Ëk iâÕ%PΧ<«è¹Zœ¿+F&x‘ÐTc¬¤GiÔá¿Ò4Œ:j¼"ÒÁËš âþîM&Ý“É~ xO_Ikp¯Ó#Ý)¥(Lg¿^«<®1izØtܯìÕ˜SHäÄÌ©T½·TÆêñ}õ¢ÐXU@çò´ÃHãsá(·½­gã 4]bL2·œ[&Û í¶°ðÏÎÕå͘ Ãêçê¶ú φãaçËs(mÆzêý¯È®s[Íð‡ôz¿Å²H„¾{ÖLVqÃóåËÆ³ak{á¶s“»–¹’÷5¸#Ê]8›™¾ÓŠ‘ºí çKˆâç‘(0Ùrvvwãƒÿgow‹õåÿÝG6|(¥®B²uÉ8AÌ UX雥ˆÓÛuê–”%™(*žhT RE÷S‰ L{Í©œBÛxà„ÑŒˆ¤bfIÌ ¤»‹$ñ„ˆÂC‰Òéíý\¾J wXY·…¢ô4ú’+ã¦N(¡ý¥‘wAá+:ºâ-–Š\XZ%á¦Ý¤í”½ù0p†”X:‰mWš¬“UˆZجû gt…¢ZùîmD#ål/®èSø‚¾$«›…Zµ”ÖÅ"Ve`é[N}¯Ô¿PK!Hd½›tŒs*RED_Metrics_Tracker-0.1.1.dist-info/RECORDÎ;s‚@†áÞß Ë"…°«À@nÍ„E\ñƯ“Œ3–Ω¾æy­ÊwŒIGŒßú;sjr^’?ôƒë⟺‘u[ë2ï$nضq