8.9 KiB
Monitoring Integration Plan for Pharmacy Integration Platform (PIP)
This document outlines how to integrate the PIP application with an existing Prometheus/Grafana/Alertmanager stack running on a remote host. The PIP application already exposes Prometheus metrics at /metrics and includes OpenTelemetry instrumentation for tracing.
Prerequisites
- Running PIP instance - The application must be accessible from the monitoring host (via network).
- Existing monitoring stack - Prometheus server, Grafana, and Alertmanager already deployed and reachable.
- Network access - Ensure the monitoring host can scrape the PIP application's metrics endpoint (default port 8000).
- Credentials (if applicable) - Any authentication tokens or basic auth required for scraping.
1. Metrics Endpoint
The PIP application exposes Prometheus-formatted metrics at:
http://<pip-host>:8000/metrics
This endpoint is already mounted in the FastAPI application (see src/main.py line 64-65). No further changes are required unless you need to change the path or add authentication.
Optional: Add Basic Auth to Metrics Endpoint
If your Prometheus server requires authentication, you can wrap the metrics endpoint with middleware. Example:
# In src/main.py after creating the app
from starlette.basic_auth import BasicAuthMiddleware
from src.infrastructure.config.settings import settings
if settings.METRICS_AUTH_USERNAME and settings.METRICS_AUTH_PASSWORD:
app.add_middleware(
BasicAuthMiddleware,
username=settings.METRICS_AUTH_USERNAME,
password=settings.METRICS_AUTH_PASSWORD,
)
Add the corresponding environment variables to your deployment.
2. Prometheus Configuration
Add a scrape job for the PIP service in your Prometheus configuration file (typically prometheus.yml).
scrape_configs:
- job_name: 'pip-api'
static_configs:
- targets: ['<pip-host>:8000'] # replace with actual host/IP
# Optional: if you enabled basic auth on /metrics
# basic_auth:
# username: <username>
# password: <password>
# Optional: TLS configuration if using HTTPS
# scheme: https
# tls_config:
# ca_file: /path/to/ca.pem
# cert_file: /path/to/client-cert.pem
# key_file: /path/to/client-key.pem
metric_relabel_configs:
# Optional: filter or relabel metrics as needed
- source_labels: [__name__]
regex: 'pip_.*'
action: keep
After updating the configuration, reload Prometheus:
curl -X POST http://<prometheus-host>:9090/-/reload
3. Grafana Dashboards
You can import a pre-built dashboard JSON (provided below) or create your own panels using the exposed metrics.
Example Dashboard JSON
Save this as pip-dashboard.json and import via Grafana UI (+ Import → Paste JSON).
{
"dashboard": {
"id": null,
"title": "Pharmacy Integration Platform",
"timezone": "browser",
"schemaVersion": 38,
"version": 1,
"refresh": "10s",
"panels": [
{
"type": "graph",
"title": "HTTP Requests Rate",
"datasource": "Prometheus",
"targets": [
{
"expr": "sum by (method, endpoint, http_status) (rate(pip_http_requests_total[5m]))",
"legendFormat": "{{method}} {{endpoint}} {{http_status}}",
"refId": "A"
}
],
"yAxes": [
{
"format": "ops",
"label": "req/s"
}
],
"gridPos": { "x": 0, "y": 0, "w": 12, "h": 8 }
},
{
"type": "graph",
"title": "Request Duration (seconds)",
"datasource": "Prometheus",
"targets": [
{
"expr": "histogram_quantile(0.95, sum by (le, method, endpoint) (rate(pip_http_request_duration_seconds_bucket[5m])))",
"legendFormat": "{{method}} {{endpoint}} 95th percentile",
"refId": "A"
}
],
"yAxes": [
{
"format": "seconds",
"label": "seconds"
}
],
"gridPos": { "x": 12, "y": 0, "w": 12, "h": 8 }
},
{
"type": "graph",
"title": "Database Query Duration",
"datasource": "Prometheus",
"targets": [
{
"expr": "histogram_quantile(0.95, sum by (le, operation) (rate(pip_db_query_duration_seconds_bucket[5m])))",
"legendFormat": "{{operation}} 95th percentile",
"refId": "A"
}
],
"yAxes": [
{
"format": "seconds",
"label": "seconds"
}
],
"gridPos": { "x": 0, "y": 8, "w": 12, "h": 8 }
},
{
"type": "graph",
"title": "Redis Operations",
"datasource": "Prometheus",
"targets": [
{
"expr": "sum by (operation) (rate(pip_redis_operations_total[5m]))",
"legendFormat": "{{operation}}",
"refId": "A"
}
],
"yAxes": [
{
"format": "ops",
"label": "ops/s"
}
],
"gridPos": { "x": 12, "y": 8, "w": 12, "h": 8 }
},
{
"type": "graph",
"title": "RabbitMQ Messages Published",
"datasource": "Prometheus",
"targets": [
{
"expr": "sum by (exchange, routing_key) (rate(pip_rabbitmq_messages_published_total[5m]))",
"legendFormat": "{{exchange}} -> {{routing_key}}",
"refId": "A"
}
],
"yAxes": [
{
"format": "ops",
"label": "msgs/s"
}
],
"gridPos": { "x": 0, "y": 16, "w": 24, "h": 8 }
}
],
"templating": {
"list": []
},
"annotations": {
"list": []
}
},
"overwrite": true
}
Import Steps
- In Grafana, click the + icon → Import.
- Paste the JSON above or upload the file.
- Select your Prometheus data source.
- Click Import.
4. Alerting Rules (Optional)
Create a rule file for Alertmanager (e.g., pip_alerts.yml) and add it to your Prometheus server.
groups:
- name: pip-alerts
rules:
- alert: HighRequestLatency
expr: histogram_quantile(0.95, sum by (le, method, endpoint) (rate(pip_http_request_duration_seconds_bucket[5m]))) > 2
for: 2m
labels:
severity: warning
annotations:
summary: "High request latency on {{ $labels.endpoint }}"
description: "95th percentile latency is above 2 seconds for {{ $labels.method }} {{ $labels.endpoint }}."
- alert: APIErrorRateHigh
expr: sum by (http_status) (rate(pip_http_requests_total{http_status=~"5.."}[5m])) / sum by (http_status) (rate(pip_http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate ({{ $value | printf \"%.2f\" }})"
description: "More than 5% of requests are returning 5xx errors."
- alert: RedisDown
expr: up{job="pip-api"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "PIP application scrape failed"
description: "Prometheus cannot scrape the PIP application metrics endpoint."
- alert: DatabaseConnectionFailures
expr: increase(pip_db_connection_errors_total[5m]) > 0
for: 2m
labels:
severity: warning
annotations:
summary: "Database connection errors detected"
description: "There have been {{ $value }} database connection errors in the last 5 minutes."
Add the file to your Prometheus server's rule files configuration and reload.
5. Verification Steps
-
Verify Metrics Endpoint
From the monitoring host, run:curl -s http://<pip-host>:8000/metrics | head -20You should see lines like
# HELP pip_http_requests_total ...and# TYPE pip_http_requests_total counter. -
Check Prometheus Targets
In Prometheus UI (http://<prometheus-host>:9090/targets), ensure thepip-apijob showsUP. -
View Dashboard
Open the imported dashboard in Grafana and verify panels populate with data. -
Test Alerts (Optional)
You can temporarily trigger an alert by modifying the threshold (e.g., setHighRequestLatencyto> 0) and verify Alertmanager fires.
6. Cleanup / Roll‑needed) later you decide howto monitor within the docker compose stack again, just edit docker-compose.yml and uncomment the monitoring services (prometheus, grafana, alertmanager) and the related volumes, then run:
docker compose -f pip-platform/docker-compose.yml up -d
Make sure the healthcheck in the pip-api service still points to /api/v1/system/health (already updated).
This plan is intended to be a one‑time setup guide. Adjust hostnames, ports, authentication, and resource limits to match your production environment.