Package: prometheus-fastapi-instrumentator
Prometheus FastAPI InstrumentatorA configurable and modular Prometheus Instrumentator for your FastAPI. Installprometheus-fastapi-instrumentatorfromPyPI. Here is
the fast track to get started with a pre-configured instrumentator. Import the
instrumentator class:fromprometheus_fastapi_instrumentatorimportInstrumentatorInstrument your app with default metrics and expose the metrics:Instrumentator().instrument(app).expose(app)Depending on your code you might have to use the following instead:instrumentator=Instrumentator().instrument(app)@app.on_event("startup")asyncdef_startup():instrumentator.expose(app)With this, your FastAPI is instrumented and metrics are ready to be scraped. The
defaults give you:Counterhttp_requests_totalwithhandler,statusandmethod. Total
number of requests.Summaryhttp_request_size_byteswithhandler. Added up total of the
content lengths of all incoming requests.Summaryhttp_response_size_byteswithhandler. Added up total of the
content lengths of all outgoing responses.Histogramhttp_request_duration_secondswithhandlerandmethod. Only a
few buckets to keep cardinality low.Histogramhttp_request_duration_highr_secondswithout any labels. Large
number of buckets (>20).In addition, following behavior is active:Status codes are grouped into2xx,3xxand so on.Requests without a matching template are grouped into the handlernone.If one of these presets does not suit your needs you can do one of multiple
things:Pick one of the already existing closures frommetricsand pass it to
the instrumentator instance. Seeherehow to do that.Create your own instrumentation function that you can pass to an
instrumentator instance. Seehereto learn how more.Don't use this package at all and just use the source code as inspiration on
how to instrument your FastAPI.Table of ContentsDisclaimerFeaturesAdvanced UsageCreating the InstrumentatorAdding metricsCreating new metricsPerform instrumentationSpecify namespace and subsystemExposing endpointContributingLicensingDisclaimerNot made for generic Prometheus instrumentation in Python. Use the Prometheus
client library for that. This packages uses it as well.All the generic middleware and instrumentation code comes with a cost in
performance that can become noticeable.FeaturesBeyond the fast track, this instrumentator ishighly configurableand it is
very easy to customize and adapt to your specific use case. Here is a list of
some of these options you may opt-in to:Regex patterns to ignore certain routes.Completely ignore untemplated routes.Control instrumentation and exposition with an env var.Rounding of latencies to a certain decimal number.Renaming of labels and the metric.Metrics endpoint can compress data with gzip.Opt-in metric to monitor the number of requests in progress.It also features amodular approach to metricsthat should instrument all
FastAPI endpoints. You can either choose from a set of already existing metrics
or create your own. And every metric function by itself can be configured as
well. You can see ready to use metricshere.Advanced UsageThis chapter contains an example on the advanced usage of the Prometheus FastAPI
Instrumentator to showcase most of it's features. Fore more concrete info check
out theautomatically generated documentation.Creating the InstrumentatorWe start by creating an instance of the Instrumentator. Notice the additionalmetricsimport. This will come in handy later.fromprometheus_fastapi_instrumentatorimportInstrumentator,metricsinstrumentator=Instrumentator(should_group_status_codes=False,should_ignore_untemplated=True,should_respect_env_var=True,should_instrument_requests_inprogress=True,excluded_handlers=[".*admin.*","/metrics"],env_var_name="ENABLE_METRICS",inprogress_name="inprogress",inprogress_labels=True,)Unlike in the fast track example, now the instrumentation and exposition will
only take place if the environment variableENABLE_METRICSistrueat
run-time. This can be helpful in larger deployments with multiple services
depending on the same base FastAPI.Adding metricsLet's say we also want to instrument the size of requests and responses. For
this we use theadd()method. This method does nothing more than taking a
function and adding it to a list. Then during run-time every time FastAPI
handles a request all functions in this list will be called while giving them a
single argument that stores useful information like the request and response
objects. If noadd()at all is used, the default metric gets added in the
background. This is what happens in the fast track example.All instrumentation functions are stored as closures in themetricsmodule.
Fore more concrete info check out theautomatically generated documentation.Closures come in handy here because it allows us to configure the functions
within.instrumentator.add(metrics.latency(buckets=(1,2,3,)))This simply adds the metric you also get in the fast track example with a
modified buckets argument. But we would also like to record the size of all
requests and responses.instrumentator.add(metrics.request_size(should_include_handler=True,should_include_method=False,should_include_status=True,metric_namespace="a",metric_subsystem="b",)).add(metrics.response_size(should_include_handler=True,should_include_method=False,should_include_status=True,metric_namespace="namespace",metric_subsystem="subsystem",))You can add as many metrics you like to the instrumentator.Creating new metricsAs already mentioned, it is possible to create custom functions to pass on toadd(). This is also how the default metrics are implemented. The documentation
and codehereis helpful to get an overview.The basic idea is that the instrumentator creates aninfoobject that contains
everything necessary for instrumentation based on the configuration of the
instrumentator. This includes the raw request and response objects but also the
modified handler, grouped status code and duration. Next, all registered
instrumentation functions are called. They getinfoas their single argument.Let's say we want to count the number of times a certain language has been
requested.fromtypingimportCallablefromprometheus_fastapi_instrumentator.metricsimportInfofromprometheus_clientimportCounterdefhttp_requested_languages_total()->Callable[[Info],None]:METRIC=Counter("http_requested_languages_total","Number of times a certain language has been requested.",labelnames=("langs",))definstrumentation(info:Info)->None:langs=set()lang_str=info.request.headers["Accept-Language"]forelementinlang_str.split(","):element=element.split(";")[0].strip().lower()langs.add(element)forlanguageinlangs:METRIC.labels(language).inc()returninstrumentationThe functionhttp_requested_languages_totalis used for persistent elements
that are stored between all instrumentation executions (for example the metric
instance itself). Next comes the closure. This function must adhere to the shown
interface. It will always get anInfoobject that contains the request,
response and a few other modified informations. For example the (grouped) status
code or the handler. Finally, the closure is returned.Important:The response object insideinfocan either be the response
object orNone. In addition, errors thrown in the handler are not caught by
the instrumentator. I recommend to check the documentation and/or the source
code before creating your own metrics.To use it, we hand over the closure to the instrumentator object.instrumentator.add(http_requested_languages_total())Perform instrumentationUp to this point, the FastAPI has not been touched at all. Everything has been
stored in theinstrumentatoronly. To actually register the instrumentation
with FastAPI, theinstrument()method has to be called.instrumentator.instrument(app)Notice that this will do nothing ifshould_respect_env_varhas been set during
construction of the instrumentator object and the respective env var is not
found.Specify namespace and subsystemYou can specify the namespace and subsystem of the metrics by passing them in
the instrument method.fromprometheus_fastapi_instrumentatorimportInstrumentator@app.on_event("startup")asyncdefstartup():Instrumentator().instrument(app,metric_namespace='myproject',metric_subsystem='myservice').expose(app)Then your metrics will contain the namespace and subsystem in the metric name.# TYPE myproject_myservice_http_request_duration_highr_seconds histogrammyproject_myservice_http_request_duration_highr_seconds_bucket{le="0.01"}0.0Exposing endpointTo expose an endpoint for the metrics either followPrometheus Python Clientand add
the endpoint manually to the FastAPI or serve it on a separate server. You can
also use the includedexposemethod. It will add an endpoint to the given
FastAPI. Withshould_gzipyou can instruct the endpoint to compress the data
as long as the client accepts gzip encoding. Prometheus for example does by
default. Beware that network bandwith is often cheaper than CPU cycles.instrumentator.expose(app,include_in_schema=False,should_gzip=True)Notice that this will to nothing ifshould_respect_env_varhas been set during
construction of the instrumentator object and the respective env var is not
found.ContributingPlease refer toCONTRIBUTING.md.ConsultDEVELOPMENT.mdfor guidance regarding development.ReadRELEASE.mdfor details about the release process.LicensingThe default license for this project is theISC License. A permissive license
functionally equivalent to the BSD 2-Clause and MIT licenses, removing some
language that is no longer necessary. SeeLICENSEfor the license
text.TheBSD 3-Clause Licenseis
used as the license for theroutingmodule. This is
due to it containing code fromelastic/apm-agent-python. BSD
3-Clause is a permissive license similar to the BSD 2-Clause License, but with a
3rd clause that prohibits others from using the name of the copyright holder or
its contributors to promote derived products without written consent. The
license text is included in the module itself.