Skip to content

Instantly share code, notes, and snippets.

@Da-Juan
Created August 23, 2023 08:43
Show Gist options
  • Save Da-Juan/645b58a34665d6f8a5e0b51df3f5c67d to your computer and use it in GitHub Desktop.
Save Da-Juan/645b58a34665d6f8a5e0b51df3f5c67d to your computer and use it in GitHub Desktop.
Prometheus exporter in Python with background metrics gathering
"""Prometheus exporter with background metrics gathering."""
import signal
import threading
import time
from typing import TYPE_CHECKING
import schedule
from flask import Flask
from prometheus_client import Gauge, make_wsgi_app
from werkzeug.middleware.dispatcher import DispatcherMiddleware
if TYPE_CHECKING:
from types import FrameType
class MetricsGatherer(threading.Thread):
"""Metrics gathering thread manager."""
def __init__(self: MetricsGatherer) -> None:
"""Initialize object."""
threading.Thread.__init__(self)
self.shutdown_flag = threading.Event()
schedule.every(10).seconds.do(update_metrics)
schedule.run_all()
def run(self: MetricsGatherer) -> None:
"""Run the thread."""
print(f"Thread #{self.ident} started")
while True:
if self.shutdown_flag.is_set():
schedule.clear()
print(f"Thread #{self.ident} stopped")
break
schedule.run_pending()
time.sleep(1)
class ServiceExit(Exception):
"""Custom exception which is used to trigger the clean exit of all running threads and the main program."""
def update_metrics() -> None:
"""Update your metrics."""
def service_shutdown(signum: int, _: FrameType) -> None:
"""Handle shutdown signals."""
print("Caught signal %d" % signum)
raise ServiceExit
signal.signal(signal.SIGTERM, service_shutdown)
signal.signal(signal.SIGINT, service_shutdown)
app = Flask(__name__)
@app.route("/")
def hello_world() -> str:
"""Serve the main app."""
return "Hello world!"
app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {
"/metrics": make_wsgi_app(),
})
my_metric = Gauge("my_metric", "My beautiful metric")
metrics_gatherer = MetricsGatherer()
metrics_gatherer.start()
try:
app.run()
except ServiceExit:
metrics_gatherer.shutdown_flag.set()
metrics_gatherer.join()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment