Add a /health endpoint using the Prometheus Python client library

1,074 views
Skip to first unread message

Paddy Newman

unread,
May 20, 2022, 3:52:13 AM5/20/22
to Prometheus Users
Hello everyone,

The following is an example of a pattern we use frequently:

import time

from prometheus_client import start_http_server
from prometheus_client.core import GaugeMetricFamily, REGISTRY

def costly_function():
    "E.g., queries someone else's API and uses up API credits, etc..."
    return ('dev', 'uat', 'prod')

class Collector:
    def collect(self):
        gauge = GaugeMetricFamily('example_gauge',
            'Example gauge', labels=["environment"])
        for environment in costly_function():
            print("adding sample for environment=%s" % environment)
            gauge.add_metric([environment], 1)
        yield gauge

REGISTRY.register(Collector())
start_http_server(8080)
print("server listening on port 8080")
while True:
    time.sleep(60)

When we hook these kinds of exporter up in Google's GKE, and expose them via ILB Services, the ILB health checks query them for health via a /healthz endpoint.

That triggers an unwanted call to the costly_function() which we'd like to avoid.

Is there a simple way to intercept the call to /healthz and return e.g., an "OK" response but without resorting to a framework like Flask or Twisted?

We're at pains to keep these exporters as simple as possible.

Thanks in advance!

Paddy Newman

unread,
May 20, 2022, 4:08:54 AM5/20/22
to Prometheus Users
For what it's worth, I ended starting the web server via http.server, like this:

class Handler(MetricsHandler):
    def do_GET(self):
        if self.path.endswith('/metrics'):
            return super().do_GET()
        self.send_response(200)
        self.send_header('Content-type', 'text/plain')
        self.end_headers()
        self.wfile.write(b'OK')

REGISTRY.register(Collector())

http.server.HTTPServer(('', 8080), Handler).serve_forever()

Reply all
Reply to author
Forward
0 new messages