From 5c2d7433f5a39d6a64dbd0147bdb9d8c2720a7df Mon Sep 17 00:00:00 2001 From: avikstroem Date: Mon, 22 Jan 2024 16:49:41 +0100 Subject: [PATCH 1/4] skip_paths support regular expressions --- starlette_exporter/middleware.py | 7 ++++--- tests/test_middleware.py | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/starlette_exporter/middleware.py b/starlette_exporter/middleware.py index 8dfbab3..183ab69 100644 --- a/starlette_exporter/middleware.py +++ b/starlette_exporter/middleware.py @@ -1,5 +1,6 @@ """ Middleware for exporting Prometheus metrics using Starlette """ import logging +import re import time from collections import OrderedDict from contextlib import suppress @@ -101,9 +102,9 @@ def __init__( self.kwargs = {} if buckets is not None: self.kwargs["buckets"] = buckets - self.skip_paths = [] + self.skip_paths: List[re.Pattern] = [] if skip_paths is not None: - self.skip_paths = skip_paths + self.skip_paths = [re.compile(path) for path in skip_paths] self.skip_methods = [] if skip_methods is not None: self.skip_methods = skip_methods @@ -264,7 +265,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if base_path and path.startswith(base_path): path = path[len(base_path) :] - if path in self.skip_paths or method in self.skip_methods: + if any(pattern.match(path) for pattern in self.skip_paths) or method in self.skip_methods: await self.app(scope, receive, send) return diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 86659b9..a5ab1d3 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -391,6 +391,13 @@ def test_skip_paths(self, testapp): metrics = client.get("/metrics").content.decode() assert """path="/health""" not in metrics + def test_skip_paths__re(self, testapp): + """test that requests doesn't appear in the counter""" + client = TestClient(testapp(skip_paths=[r"/h.*"])) + client.get("/health") + metrics = client.get("/metrics").content.decode() + assert """path="/health""" not in metrics + def test_skip_methods(self, testapp): """test that requests doesn't appear in the counter""" client = TestClient(testapp(skip_methods=["POST"])) From d4b2e67c3822e827108c3ac64d46806f4f18de59 Mon Sep 17 00:00:00 2001 From: bunny-therapist Date: Mon, 22 Jan 2024 20:40:43 +0100 Subject: [PATCH 2/4] Ensure backwards compatibility for skip_paths Use fullmatch instead of match --- starlette_exporter/middleware.py | 2 +- tests/test_middleware.py | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/starlette_exporter/middleware.py b/starlette_exporter/middleware.py index 183ab69..fa30197 100644 --- a/starlette_exporter/middleware.py +++ b/starlette_exporter/middleware.py @@ -265,7 +265,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if base_path and path.startswith(base_path): path = path[len(base_path) :] - if any(pattern.match(path) for pattern in self.skip_paths) or method in self.skip_methods: + if any(pattern.fullmatch(path) for pattern in self.skip_paths) or method in self.skip_methods: await self.app(scope, receive, send) return diff --git a/tests/test_middleware.py b/tests/test_middleware.py index a5ab1d3..3afd779 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -392,12 +392,19 @@ def test_skip_paths(self, testapp): assert """path="/health""" not in metrics def test_skip_paths__re(self, testapp): - """test that requests doesn't appear in the counter""" + """test skip_paths using regular expression""" client = TestClient(testapp(skip_paths=[r"/h.*"])) client.get("/health") metrics = client.get("/metrics").content.decode() assert """path="/health""" not in metrics + def test_skip_paths__re_partial(self, testapp): + """test skip_paths using regular expression""" + client = TestClient(testapp(skip_paths=[r"/h"])) + client.get("/health") + metrics = client.get("/metrics").content.decode() + assert """path="/health""" in metrics + def test_skip_methods(self, testapp): """test that requests doesn't appear in the counter""" client = TestClient(testapp(skip_methods=["POST"])) From a7690cb69646b24d0709db388a01c43eaf2a23d4 Mon Sep 17 00:00:00 2001 From: bunny-therapist Date: Mon, 22 Jan 2024 20:41:54 +0100 Subject: [PATCH 3/4] Update README for skip_paths --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4ec779..3fa61f8 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ retrieves a value from the `Request` object. [See below](#labels) for examples. `buckets`: accepts an optional list of numbers to use as histogram buckets. The default value is `None`, which will cause the library to fall back on the Prometheus defaults (currently `[0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5, 10.0]`). -`skip_paths`: accepts an optional list of paths that will not collect metrics. The default value is `None`, which will cause the library to collect metrics on every requested path. This option is useful to avoid collecting metrics on health check, readiness or liveness probe endpoints. +`skip_paths`: accepts an optional list of paths - or regular expressions for paths - that will not collect metrics. The default value is `None`, which will cause the library to collect metrics on every requested path. This option is useful to avoid collecting metrics on health check, readiness or liveness probe endpoints. `skip_methods`: accepts an optional list of methods that will not collect metrics. The default value is `None`, which will cause the library to collect request metrics with each method. This option is useful to avoid collecting metrics on requests related to the communication description for endpoints. From 677c5129b76ab56518a517a12305e28dff58adfd Mon Sep 17 00:00:00 2001 From: bunny-therapist <87039365+bunny-therapist@users.noreply.github.com> Date: Sat, 27 Jan 2024 22:02:19 +0100 Subject: [PATCH 4/4] Change dashes to commas in README Co-authored-by: Steve Hillier --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fa61f8..ecc4776 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ retrieves a value from the `Request` object. [See below](#labels) for examples. `buckets`: accepts an optional list of numbers to use as histogram buckets. The default value is `None`, which will cause the library to fall back on the Prometheus defaults (currently `[0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5, 10.0]`). -`skip_paths`: accepts an optional list of paths - or regular expressions for paths - that will not collect metrics. The default value is `None`, which will cause the library to collect metrics on every requested path. This option is useful to avoid collecting metrics on health check, readiness or liveness probe endpoints. +`skip_paths`: accepts an optional list of paths, or regular expressions for paths, that will not collect metrics. The default value is `None`, which will cause the library to collect metrics on every requested path. This option is useful to avoid collecting metrics on health check, readiness or liveness probe endpoints. `skip_methods`: accepts an optional list of methods that will not collect metrics. The default value is `None`, which will cause the library to collect request metrics with each method. This option is useful to avoid collecting metrics on requests related to the communication description for endpoints.