Skip to content

Commit

Permalink
Merge pull request #30 from claws/add_render_function
Browse files Browse the repository at this point in the history
add metrics render function
  • Loading branch information
claws committed Jul 23, 2018
2 parents bc99757 + 7948c1d commit 1fe3dbe
Show file tree
Hide file tree
Showing 20 changed files with 632 additions and 124 deletions.
108 changes: 78 additions & 30 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,40 +33,39 @@ and exposed via a HTTP endpoint.
.. code-block:: python
#!/usr/bin/env python
'''
"""
This example demonstrates how a single Counter metric collector can be created
and exposed via a HTTP endpoint.
'''
"""
import asyncio
import socket
from aioprometheus import Counter, Service
if __name__ == '__main__':
if __name__ == "__main__":
loop = asyncio.get_event_loop()
svr = Service()
async def main(svr: Service) -> None:
events_counter = Counter(
"events",
"Number of events.",
const_labels={'host': socket.gethostname()})
events_counter = Counter(
"events", "Number of events.", const_labels={"host": socket.gethostname()}
)
svr.register(events_counter)
await svr.start(addr="127.0.0.1", port=5000)
print(f"Serving prometheus metrics on: {svr.metrics_url}")
svr.register(events_counter)
# Now start another coroutine to periodically update a metric to
# simulate the application making some progress.
async def updater(c: Counter):
while True:
c.inc({"kind": "timer_expiry"})
await asyncio.sleep(1.0)
loop.run_until_complete(svr.start(addr="127.0.0.1"))
print(f'Serving prometheus metrics on: {svr.metrics_url}')
async def updater(m: Counter):
# Periodically update the metric to simulate some progress
# happening in a real application.
while True:
m.inc({'kind': 'timer_expiry'})
await asyncio.sleep(1.0)
await updater(events_counter)
loop = asyncio.get_event_loop()
svr = Service()
try:
loop.run_until_complete(updater(events_counter))
loop.run_until_complete(main(svr))
except KeyboardInterrupt:
pass
finally:
Expand Down Expand Up @@ -96,7 +95,7 @@ The example script can be run using:
(venv) $ cd examples
(venv) $ python simple-example.py
Serving prometheus metrics on: http://127.0.0.1:50624/metrics
Serving prometheus metrics on: http://127.0.0.1:5000/metrics
In another terminal fetch the metrics using the ``curl`` command line tool
to verify they can be retrieved by Prometheus server.
Expand All @@ -105,7 +104,7 @@ By default metrics will be returned in plan text format.

.. code-block:: console
$ curl http://127.0.0.1:50624/metrics
$ curl http://127.0.0.1:5000/metrics
# HELP events Number of events.
# TYPE events counter
events{host="alpha",kind="timer_expiry"} 33
Expand All @@ -115,7 +114,7 @@ to read on the command line.

.. code-block:: console
$ curl http://127.0.0.1:50624/metrics -H "ACCEPT: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
$ curl http://127.0.0.1:5000/metrics -H "ACCEPT: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
The metrics service also responds to requests sent to its ``/`` route. The
response is simple HTML. This route can be useful as a Kubernetes ``/healthz``
Expand All @@ -124,15 +123,64 @@ to serialize a full metrics response.

.. code-block:: console
$ curl http://127.0.0.1:50624/
$ curl http://127.0.0.1:5000/
<html><body><a href='/metrics'>metrics</a></body></html>
A number of convenience decorator functions are also available to assist with
updating metrics.
The aioprometheus package provides a number of convenience decorator
functions that can assist with updating metrics.

There ``examples`` directory contains many examples showing how to use the
aioprometheus package. The ``app-example.py`` file will likely be of interest
as it provides a more representative application example that the simple
example shown above.

Examples in the ``examples/frameworks`` directory show how aioprometheus can
be used within existing aiohttp, quart and vibora applications instead of
creating a separate aioprometheus.Service endpoint to handle metrics. The
vibora example is shown below.

.. code-block:: python
#!/usr/bin/env python
"""
Sometimes you want to expose Prometheus metrics from within an existing web
service and don't want to start a separate Prometheus metrics server.
This example uses the aioprometheus package to add Prometheus instrumentation
to a Vibora application. In this example a registry and a counter metric is
instantiated. A '/metrics' route is added to the application and the render
function from aioprometheus is called to format the metrics into the
appropriate format.
"""
from aioprometheus import render, Counter, Registry
from vibora import Vibora, Request, Response
app = Vibora(__name__)
app.registry = Registry()
app.events_counter = Counter("events", "Number of events.")
app.registry.register(app.events_counter)
@app.route("/")
async def hello(request: Request):
app.events_counter.inc({"path": "/"})
return Response(b"hello")
@app.route("/metrics")
async def handle_metrics(request: Request):
"""
Negotiate a response format by inspecting the ACCEPTS headers and selecting
the most efficient format. Render metrics in the registry into the chosen
format and return a response.
"""
content, http_headers = render(app.registry, [request.headers.get("accept")])
return Response(content, headers=http_headers)
There are more examples in the ``examples`` directory. The ``app-example.py``
file will likely be of interest as it provides a more representative
application example.
app.run()
License
Expand Down
29 changes: 19 additions & 10 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ The example script can be run using:
(venv) $ cd examples
(venv) $ python simple-example.py
Serving prometheus metrics on: http://127.0.0.1:50624/metrics
Serving prometheus metrics on: http://127.0.0.1:5000/metrics
In another terminal fetch the metrics using the ``curl`` command line tool
to verify they can be retrieved by Prometheus server.
Expand All @@ -73,12 +73,12 @@ By default metrics will be returned in plan text format.

.. code-block:: console
$ curl http://127.0.0.1:50624/metrics
$ curl http://127.0.0.1:5000/metrics
# HELP events Number of events.
# TYPE events counter
events{host="alpha",kind="timer_expiry"} 33
$ curl http://127.0.0.1:50624/metrics -H 'Accept: text/plain; version=0.0.4'
$ curl http://127.0.0.1:5000/metrics -H 'Accept: text/plain; version=0.0.4'
# HELP events Number of events.
# TYPE events counter
events{host="alpha",kind="timer_expiry"} 36
Expand All @@ -88,7 +88,7 @@ to read on the command line.

.. code-block:: console
$ curl http://127.0.0.1:50624/metrics -H "ACCEPT: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
$ curl http://127.0.0.1:5000/metrics -H "ACCEPT: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
The metrics service also responds to requests sent to its ``/`` route. The
response is simple HTML. This route can be useful as a Kubernetes health
Expand All @@ -97,15 +97,24 @@ serialize a full metrics response.

.. code-block:: console
$ curl http://127.0.0.1:50624/
$ curl http://127.0.0.1:5000/
<html><body><a href='/metrics'>metrics</a></body></html>
A number of convenience decorator functions are also available to assist with
updating metrics.
The aioprometheus package provides a number of convenience decorator
functions that can assist with updating metrics.

There are more examples in the ``examples`` directory. The ``app-example.py``
file will likely be of interest as it provides a more representative
application example.
There ``examples`` directory contains many examples showing how to use the
aioprometheus package. The ``app-example.py`` file will likely be of interest
as it provides a more representative application example that the simple
example shown above.

Examples in the ``examples/frameworks`` directory show how aioprometheus can
be used within existing aiohttp, quart and vibora applications instead of
creating a separate aioprometheus.Service endpoint to handle metrics. The
vibora example is shown below.

.. literalinclude:: ../examples/frameworks/vibora-example.py
:language: python3


License
Expand Down
27 changes: 19 additions & 8 deletions docs/user/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ The example script can be run using:
(venv) $ cd examples
(venv) $ python simple-example.py
Serving prometheus metrics on: http://127.0.0.1:50624/metrics
Serving prometheus metrics on: http://127.0.0.1:5000/metrics
In another terminal fetch the metrics using the ``curl`` command line tool
to verify they can be retrieved by Prometheus server.
Expand All @@ -231,12 +231,12 @@ By default metrics will be returned in plan text format.

.. code-block:: console
$ curl http://127.0.0.1:50624/metrics
$ curl http://127.0.0.1:5000/metrics
# HELP events Number of events.
# TYPE events counter
events{host="alpha",kind="timer_expiry"} 33
$ curl http://127.0.0.1:50624/metrics -H 'Accept: text/plain; version=0.0.4'
$ curl http://127.0.0.1:5000/metrics -H 'Accept: text/plain; version=0.0.4'
# HELP events Number of events.
# TYPE events counter
events{host="alpha",kind="timer_expiry"} 36
Expand All @@ -246,7 +246,7 @@ to read on the command line.

.. code-block:: console
$ curl http://127.0.0.1:50624/metrics -H "ACCEPT: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
$ curl http://127.0.0.1:5000/metrics -H "ACCEPT: application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
The metrics service also responds to requests sent to its ``/`` route. The
response is simple HTML. This route can be useful as a Kubernetes ``/healthz``
Expand All @@ -255,7 +255,7 @@ to serialize a full metrics response.

.. code-block:: console
$ curl http://127.0.0.1:50624/
$ curl http://127.0.0.1:5000/
<html><body><a href='/metrics'>metrics</a></body></html>
Expand All @@ -274,11 +274,22 @@ The example can be run using
.. code-block:: console
(env) $ python app-example.py
Serving prometheus metrics on: http://127.0.0.1:50624/metrics
Serving prometheus metrics on: http://127.0.0.1:5000/metrics
You can use the ``curl`` command line tool to fetch metrics manually or use
the helper script described in the next section.

Frameworks Example
++++++++++++++++++

The aioprometheus package can also be used within other web framework based
applications such as ``aiohttp``, ``quart`` and ``vibora`` applications.
This usage approach removes the need to create a separate server endpoint
to handle metrics. The vibora example is shown below.

.. literalinclude:: ../../examples/frameworks/vibora-example.py
:language: python3


Checking examples using helper script
-------------------------------------
Expand Down Expand Up @@ -307,7 +318,7 @@ Example:

.. code-block:: console
$ python metrics-fetcher.py --url=http://127.0.0.1:50624/metrics --format=text --interval=2.0
$ python metrics-fetcher.py --url=http://127.0.0.1:5000/metrics --format=text --interval=2.0
Checking Example using Prometheus
Expand All @@ -334,7 +345,7 @@ we can create a minimal configuration file to scrape the example application.
scrape_timeout: 10s
target_groups:
- targets: ['localhost:50624']
- targets: ['localhost:5000']
labels:
group: 'dev'
Expand Down
16 changes: 14 additions & 2 deletions examples/app-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,25 @@
class ExampleApp(object):
"""
An example application that demonstrates how ``aioprometheus`` can be
used within a Python async application.
integrated and used within a Python application built upon asyncio.
This application attempts to simulate a long running distributed system
process, say a socket relay or some kind of message adapter. It is
intentionally not hosting an existing web service in the application.
In this case the aioprometheus.Service object is used to provide a
new HTTP endpoint that can be used to expose Prometheus metrics on.
If this application was a web service (i.e. already had an existing web
interface) then the aioprometheus.Service object could be used as before
to add another web interface or a different approach could be used that
provides a metrics handler function for use with the existing web service.
"""

def __init__(
self,
metrics_host="127.0.0.1",
metrics_port: int = 0,
metrics_port: int = 5000,
loop: BaseEventLoop = None,
):

Expand Down
38 changes: 38 additions & 0 deletions examples/frameworks/aiohttp-example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python
"""
Sometimes you want to expose Prometheus metrics from within an existing web
service and don't want to start a separate Prometheus metrics server.
This example uses the aioprometheus package to add Prometheus instrumentation
to an aiohttp application. In this example a registry and a counter metric is
instantiated. A '/metrics' route is added to the application and the render
function from aioprometheus is called to format the metrics into the
appropriate format.
"""

from aiohttp import web
from aiohttp.hdrs import ACCEPT
from aioprometheus import render, Counter, Registry


app = web.Application()
app.registry = Registry()
app.events_counter = Counter("events", "Number of events.")
app.registry.register(app.events_counter)


async def handle_root(request):
app.events_counter.inc({"path": "/"})
text = "Hello aiohttp"
return web.Response(text=text)


async def handle_metrics(request):
content, http_headers = render(app.registry, request.headers.getall(ACCEPT, []))
return web.Response(body=content, headers=http_headers)


app.add_routes([web.get("/", handle_root), web.get("/metrics", handle_metrics)])


web.run_app(app)

0 comments on commit 1fe3dbe

Please sign in to comment.