Paramjit Singh commited on
Commit
46548f5
Β·
unverified Β·
2 Parent(s): e0308089fe37a6

Merge pull request #301 from saurabhhhcodes/devops/prometheus-metrics-295

Browse files
backend/app/main.py CHANGED
@@ -19,6 +19,7 @@ from slowapi.middleware import SlowAPIMiddleware
19
  from app.config import get_settings
20
  from app.rate_limit import limiter
21
  from app.database import init_db, get_db
 
22
  from app.rag.vectorstore import get_chroma_client
23
  from app.scheduler import start_scheduler, stop_scheduler
24
 
@@ -170,6 +171,8 @@ app.include_router(chat_router, prefix="/api/v1")
170
  app.include_router(github_router, prefix="/api/v1")
171
  app.include_router(admin_router, prefix="/api/v1")
172
 
 
 
173
 
174
  # ── Health Check ─────────────────────────────────────
175
  @app.get("/api/health")
 
19
  from app.config import get_settings
20
  from app.rate_limit import limiter
21
  from app.database import init_db, get_db
22
+ from app.observability import setup_prometheus_metrics
23
  from app.rag.vectorstore import get_chroma_client
24
  from app.scheduler import start_scheduler, stop_scheduler
25
 
 
171
  app.include_router(github_router, prefix="/api/v1")
172
  app.include_router(admin_router, prefix="/api/v1")
173
 
174
+ setup_prometheus_metrics(app)
175
+
176
 
177
  # ── Health Check ─────────────────────────────────────
178
  @app.get("/api/health")
backend/app/observability.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Prometheus instrumentation for the FastAPI application."""
2
+
3
+ import sys
4
+
5
+ try:
6
+ import resource
7
+ except ImportError: # pragma: no cover - resource is unavailable on some platforms.
8
+ resource = None
9
+
10
+ from fastapi import FastAPI
11
+ from prometheus_client import Gauge
12
+ from prometheus_fastapi_instrumentator import Instrumentator
13
+
14
+ APP_PROCESS_RSS_BYTES = Gauge(
15
+ "app_process_resident_memory_bytes",
16
+ "Resident memory used by the backend process in bytes.",
17
+ )
18
+
19
+
20
+ def _get_process_rss_bytes() -> float:
21
+ if resource is None:
22
+ return 0.0
23
+
24
+ usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
25
+ if sys.platform == "darwin":
26
+ return float(usage)
27
+ return float(usage * 1024)
28
+
29
+
30
+ APP_PROCESS_RSS_BYTES.set_function(_get_process_rss_bytes)
31
+
32
+
33
+ def setup_prometheus_metrics(app: FastAPI) -> Instrumentator:
34
+ """Expose process and HTTP metrics on ``/metrics`` for Prometheus."""
35
+ instrumentator = Instrumentator(
36
+ should_group_status_codes=True,
37
+ should_ignore_untemplated=True,
38
+ excluded_handlers=["/metrics"],
39
+ )
40
+ instrumentator.instrument(app).expose(
41
+ app,
42
+ endpoint="/metrics",
43
+ include_in_schema=False,
44
+ )
45
+ app.state.prometheus_instrumentator = instrumentator
46
+ return instrumentator
backend/requirements.txt CHANGED
@@ -55,6 +55,7 @@ huggingface-hub
55
  # Production
56
  gunicorn
57
  slowapi
 
58
 
59
  # File Validation
60
  #sudo apt-get install libmagic1 // for Debian/Ubuntu
 
55
  # Production
56
  gunicorn
57
  slowapi
58
+ prometheus-fastapi-instrumentator
59
 
60
  # File Validation
61
  #sudo apt-get install libmagic1 // for Debian/Ubuntu
backend/tests/test_observability.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def test_metrics_endpoint_exposes_prometheus_payload(client):
2
+ client.get("/api/health")
3
+
4
+ response = client.get("/metrics")
5
+
6
+ assert response.status_code == 200
7
+ assert response.headers["content-type"].startswith("text/plain")
8
+
9
+ body = response.text
10
+ assert "python_info" in body
11
+ assert "app_process_resident_memory_bytes" in body
12
+ assert "http_requests_total" in body
13
+ assert "/api/health" in body