Skip to content

Commit

Permalink
♻️ Wrap adding a new metric in a try block to prevent errors when add…
Browse files Browse the repository at this point in the history
…ing new middlewares
  • Loading branch information
tiangolo committed Jun 17, 2022
1 parent 2150301 commit 601b642
Showing 1 changed file with 15 additions and 17 deletions.
32 changes: 15 additions & 17 deletions prometheus_fastapi_instrumentator/metrics.py
Expand Up @@ -542,12 +542,15 @@ def default(
if latency_lowr_buckets[-1] != float("inf"):
latency_lowr_buckets = latency_lowr_buckets + (float("inf"),)

registry_names = registry._get_names(registry)

total_name = "http_requests_total"
if total_name not in registry_names:
try:
# Starlette will call app.build_middleware_stack() with every new middleware
# added, which will call all this again, which will make the registry complain
# about duplicated metrics.
# The Python Prometheus client currently doesn't seem to have a way to verify
# if adding a metric will cause errors or not, so the only way to handle it
# seems to be with this try block.
TOTAL = Counter(
name=total_name,
name="http_requests_total",
documentation="Total number of requests by method, status and handler.",
labelnames=(
"method",
Expand All @@ -559,10 +562,8 @@ def default(
registry=registry,
)

in_size_name = "http_request_size_bytes"
if in_size_name not in registry_names:
IN_SIZE = Summary(
name=in_size_name,
name="http_request_size_bytes",
documentation=(
"Content length of incoming requests by handler. "
"Only value of header is respected. Otherwise ignored. "
Expand All @@ -574,10 +575,8 @@ def default(
registry=registry,
)

out_size_name = "http_response_size_bytes"
if out_size_name not in registry_names:
OUT_SIZE = Summary(
name=out_size_name,
name="http_response_size_bytes",
documentation=(
"Content length of outgoing responses by handler. "
"Only value of header is respected. Otherwise ignored. "
Expand All @@ -589,10 +588,8 @@ def default(
registry=registry,
)

latency_highr_name = "http_request_duration_highr_seconds"
if latency_highr_name not in registry_names:
LATENCY_HIGHR = Histogram(
name=latency_highr_name,
name="http_request_duration_highr_seconds",
documentation=(
"Latency with many buckets but no API specific labels. "
"Made for more accurate percentile calculations. "
Expand All @@ -603,10 +600,8 @@ def default(
registry=registry,
)

latency_lowr_name = "http_request_duration_seconds"
if latency_lowr_name not in registry_names:
LATENCY_LOWR = Histogram(
name=latency_lowr_name,
name="http_request_duration_seconds",
documentation=(
"Latency with only few buckets by handler. "
"Made to be only used if aggregation by handler is important. "
Expand All @@ -617,6 +612,9 @@ def default(
subsystem=metric_subsystem,
registry=registry,
)
except ValueError as e:
if "Duplicated timeseries in CollectorRegistry:" not in e.args[0]:
raise e

def instrumentation(info: Info) -> None:
TOTAL.labels(info.method, info.modified_status, info.modified_handler).inc()
Expand Down

0 comments on commit 601b642

Please sign in to comment.