claws / aioprometheus

A Prometheus Python client library for asyncio-based applications
175 stars 21 forks source link

metrics handler to existing server #27

Closed benitogf closed 6 years ago

benitogf commented 6 years ago

hello, would be nice to include some documentation on how to do something like:

from aiohttp import web
from aioprometheus import Service

prometheus_service = Service()

async def handle(request):
    text = "Hello aiohttp"
    return web.Response(text=text)

app = web.Application()
app.router.add_get('/', handle)
app.router.add_get('/metrics', prometheus_service.handle_metrics)

web.run_app(app)
claws commented 6 years ago

I think the following example code demonstrates how one could implement what you are asking for.

from aiohttp import web
from aioprometheus import Counter, Service

prometheus_service = Service()
events_counter = Counter("events", "Number of events.")
prometheus_service.register(events_counter)

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

app = web.Application()
app.router.add_get('/', handle)
app.router.add_get('/metrics', prometheus_service.handle_metrics)
web.run_app(app)

Which I then run using:

(venv) $ python example.py 
======== Running on http://0.0.0.0:8080 ========
(Press CTRL+C to quit)

Then in a separate shell I use curl to access the metrics route (before an metrics have been updated), then access the '/' route to trigger a metrics update and finally access the metrics route again to demonstrate the response containing metrics data.

(venv) $ curl http://0.0.0.0:8080/metrics
# HELP events Number of events.
# TYPE events counter
(venv) $ curl http://0.0.0.0:8080/
Hello aiohttp
(venv) $ curl http://0.0.0.0:8080/metrics
# HELP events Number of events.
# TYPE events counter
events{path="/"} 1

Your use case (exactly as written) is not one that I have needed so far. This is not to say that it is not useful, its just that I don't currently use this library that way. I typically expose the Prometheus metrics on a separate port from the main service (which in my case is not typically a web app but some kind of long running async streaming data source or sink). For this reason the current implementation of the Service object includes its own aiohttp.web.Application instance that provides its own routes and it expects to be started and stopped. This is slightly different to your example in which you want to expose the metrics from your own (separate) aiohttp.web.Application.

So, without your explicit code example showing what you wanted I would probably implement an alternative solution using the app.on_startup and app.on_cleanup method calls to async start and later stop the aiorometheus Service object as part of the app lifecycle. More detail can be found here. If this approach is of interest I can provide an example.

Hope this helps.

benitogf commented 6 years ago

Thanks for your quick and detailed response, the use case is just as you described above since I need to add prometheus instrumentation to several web services and I don't want to start it on a separate port, think that this project could support both self and external server with minor modifications to the service script, would you be willing to consider this?

claws commented 6 years ago

Since your request I have been thinking about refactoring the library to support this case. I think such an approach could also be used in Quart apps too.

benitogf commented 6 years ago

nice :+1: