├── README.md ├── docker-compose.yaml ├── fastapi-collection.json ├── grafana-dashboard.json └── prometheus.yml /README.md: -------------------------------------------------------------------------------- 1 | ## Become a Cloud and DevOps Engineer 2 | 3 | Learn every tool that matters: https://rayanslim.com 4 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | fastapi-app: 5 | image: rslim087/fastapi-prometheus:latest 6 | ports: 7 | - "8000:8000" # Assuming your FastAPI app runs on port 8000 8 | networks: 9 | - monitoring 10 | 11 | prometheus: 12 | image: prom/prometheus:v2.37.0 13 | volumes: 14 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 15 | ports: 16 | - "9090:9090" 17 | networks: 18 | - monitoring 19 | 20 | grafana: 21 | image: grafana/grafana:9.0.0 22 | environment: 23 | - GF_SECURITY_ADMIN_PASSWORD=admin 24 | ports: 25 | - "3000:3000" 26 | networks: 27 | - monitoring 28 | 29 | networks: 30 | monitoring: -------------------------------------------------------------------------------- /fastapi-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "b1234567-89ab-cdef-0123-456789abcdef", 4 | "name": "FastAPI Metrics App", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "Root", 10 | "request": { 11 | "method": "GET", 12 | "header": [], 13 | "url": { 14 | "raw": "http://localhost:8000/", 15 | "protocol": "http", 16 | "host": [ 17 | "localhost" 18 | ], 19 | "port": "8000", 20 | "path": [ 21 | "" 22 | ] 23 | } 24 | }, 25 | "response": [] 26 | }, 27 | { 28 | "name": "Create Item", 29 | "request": { 30 | "method": "POST", 31 | "header": [ 32 | { 33 | "key": "Content-Type", 34 | "value": "application/json" 35 | } 36 | ], 37 | "body": { 38 | "mode": "raw", 39 | "raw": "{\n \"name\": \"Test Item\"\n}" 40 | }, 41 | "url": { 42 | "raw": "http://localhost:8000/items", 43 | "protocol": "http", 44 | "host": [ 45 | "localhost" 46 | ], 47 | "port": "8000", 48 | "path": [ 49 | "items" 50 | ] 51 | } 52 | }, 53 | "response": [] 54 | }, 55 | { 56 | "name": "Get Item", 57 | "request": { 58 | "method": "GET", 59 | "header": [], 60 | "url": { 61 | "raw": "http://localhost:8000/items/1", 62 | "protocol": "http", 63 | "host": [ 64 | "localhost" 65 | ], 66 | "port": "8000", 67 | "path": [ 68 | "items", 69 | "1" 70 | ] 71 | } 72 | }, 73 | "response": [] 74 | }, 75 | { 76 | "name": "Update Item", 77 | "request": { 78 | "method": "PUT", 79 | "header": [ 80 | { 81 | "key": "Content-Type", 82 | "value": "application/json" 83 | } 84 | ], 85 | "body": { 86 | "mode": "raw", 87 | "raw": "{\n \"name\": \"Updated Item\"\n}" 88 | }, 89 | "url": { 90 | "raw": "http://localhost:8000/items/1", 91 | "protocol": "http", 92 | "host": [ 93 | "localhost" 94 | ], 95 | "port": "8000", 96 | "path": [ 97 | "items", 98 | "1" 99 | ] 100 | } 101 | }, 102 | "response": [] 103 | }, 104 | { 105 | "name": "Delete Item", 106 | "request": { 107 | "method": "DELETE", 108 | "header": [], 109 | "url": { 110 | "raw": "http://localhost:8000/items/1", 111 | "protocol": "http", 112 | "host": [ 113 | "localhost" 114 | ], 115 | "port": "8000", 116 | "path": [ 117 | "items", 118 | "1" 119 | ] 120 | } 121 | }, 122 | "response": [] 123 | }, 124 | { 125 | "name": "Get Metrics", 126 | "request": { 127 | "method": "GET", 128 | "header": [], 129 | "url": { 130 | "raw": "http://localhost:8000/metrics", 131 | "protocol": "http", 132 | "host": [ 133 | "localhost" 134 | ], 135 | "port": "8000", 136 | "path": [ 137 | "metrics" 138 | ] 139 | } 140 | }, 141 | "response": [] 142 | } 143 | ] 144 | } 145 | -------------------------------------------------------------------------------- /grafana-dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "type": "dashboard" 12 | } 13 | ] 14 | }, 15 | "editable": true, 16 | "gnetId": null, 17 | "graphTooltip": 0, 18 | "id": 1, 19 | "links": [], 20 | "panels": [ 21 | { 22 | "aliasColors": {}, 23 | "bars": false, 24 | "dashLength": 10, 25 | "dashes": false, 26 | "datasource": "Prometheus", 27 | "fieldConfig": { 28 | "defaults": { 29 | "custom": {} 30 | }, 31 | "overrides": [] 32 | }, 33 | "fill": 1, 34 | "fillGradient": 0, 35 | "gridPos": { 36 | "h": 8, 37 | "w": 12, 38 | "x": 0, 39 | "y": 0 40 | }, 41 | "hiddenSeries": false, 42 | "id": 2, 43 | "legend": { 44 | "avg": false, 45 | "current": false, 46 | "max": false, 47 | "min": false, 48 | "show": true, 49 | "total": false, 50 | "values": false 51 | }, 52 | "lines": true, 53 | "linewidth": 1, 54 | "nullPointMode": "null", 55 | "options": { 56 | "alertThreshold": true 57 | }, 58 | "percentage": false, 59 | "pluginVersion": "7.2.0", 60 | "pointradius": 2, 61 | "points": false, 62 | "renderer": "flot", 63 | "seriesOverrides": [], 64 | "spaceLength": 10, 65 | "stack": false, 66 | "steppedLine": false, 67 | "targets": [ 68 | { 69 | "expr": "rate(http_request_total[1m])", 70 | "interval": "", 71 | "legendFormat": "{{method}} {{path}}", 72 | "refId": "A" 73 | } 74 | ], 75 | "thresholds": [], 76 | "timeFrom": null, 77 | "timeRegions": [], 78 | "timeShift": null, 79 | "title": "Request Rate", 80 | "tooltip": { 81 | "shared": true, 82 | "sort": 0, 83 | "value_type": "individual" 84 | }, 85 | "type": "graph", 86 | "xaxis": { 87 | "buckets": null, 88 | "mode": "time", 89 | "name": null, 90 | "show": true, 91 | "values": [] 92 | }, 93 | "yaxes": [ 94 | { 95 | "format": "short", 96 | "label": null, 97 | "logBase": 1, 98 | "max": null, 99 | "min": null, 100 | "show": true 101 | }, 102 | { 103 | "format": "short", 104 | "label": null, 105 | "logBase": 1, 106 | "max": null, 107 | "min": null, 108 | "show": true 109 | } 110 | ], 111 | "yaxis": { 112 | "align": false, 113 | "alignLevel": null 114 | } 115 | }, 116 | { 117 | "aliasColors": {}, 118 | "bars": false, 119 | "dashLength": 10, 120 | "dashes": false, 121 | "datasource": "Prometheus", 122 | "fieldConfig": { 123 | "defaults": { 124 | "custom": {} 125 | }, 126 | "overrides": [] 127 | }, 128 | "fill": 1, 129 | "fillGradient": 0, 130 | "gridPos": { 131 | "h": 8, 132 | "w": 12, 133 | "x": 12, 134 | "y": 0 135 | }, 136 | "hiddenSeries": false, 137 | "id": 4, 138 | "legend": { 139 | "avg": false, 140 | "current": false, 141 | "max": false, 142 | "min": false, 143 | "show": true, 144 | "total": false, 145 | "values": false 146 | }, 147 | "lines": true, 148 | "linewidth": 1, 149 | "nullPointMode": "null", 150 | "options": { 151 | "alertThreshold": true 152 | }, 153 | "percentage": false, 154 | "pluginVersion": "7.2.0", 155 | "pointradius": 2, 156 | "points": false, 157 | "renderer": "flot", 158 | "seriesOverrides": [], 159 | "spaceLength": 10, 160 | "stack": false, 161 | "steppedLine": false, 162 | "targets": [ 163 | { 164 | "expr": "rate(http_request_duration_seconds_sum[1m]) / rate(http_request_duration_seconds_count[1m])", 165 | "interval": "", 166 | "legendFormat": "{{method}} {{path}}", 167 | "refId": "A" 168 | } 169 | ], 170 | "thresholds": [], 171 | "timeFrom": null, 172 | "timeRegions": [], 173 | "timeShift": null, 174 | "title": "Average Response Time", 175 | "tooltip": { 176 | "shared": true, 177 | "sort": 0, 178 | "value_type": "individual" 179 | }, 180 | "type": "graph", 181 | "xaxis": { 182 | "buckets": null, 183 | "mode": "time", 184 | "name": null, 185 | "show": true, 186 | "values": [] 187 | }, 188 | "yaxes": [ 189 | { 190 | "format": "s", 191 | "label": null, 192 | "logBase": 1, 193 | "max": null, 194 | "min": null, 195 | "show": true 196 | }, 197 | { 198 | "format": "short", 199 | "label": null, 200 | "logBase": 1, 201 | "max": null, 202 | "min": null, 203 | "show": true 204 | } 205 | ], 206 | "yaxis": { 207 | "align": false, 208 | "alignLevel": null 209 | } 210 | }, 211 | { 212 | "aliasColors": {}, 213 | "bars": false, 214 | "dashLength": 10, 215 | "dashes": false, 216 | "datasource": "Prometheus", 217 | "fieldConfig": { 218 | "defaults": { 219 | "custom": {} 220 | }, 221 | "overrides": [] 222 | }, 223 | "fill": 1, 224 | "fillGradient": 0, 225 | "gridPos": { 226 | "h": 8, 227 | "w": 12, 228 | "x": 0, 229 | "y": 8 230 | }, 231 | "hiddenSeries": false, 232 | "id": 6, 233 | "legend": { 234 | "avg": false, 235 | "current": false, 236 | "max": false, 237 | "min": false, 238 | "show": true, 239 | "total": false, 240 | "values": false 241 | }, 242 | "lines": true, 243 | "linewidth": 1, 244 | "nullPointMode": "null", 245 | "options": { 246 | "alertThreshold": true 247 | }, 248 | "percentage": false, 249 | "pluginVersion": "7.2.0", 250 | "pointradius": 2, 251 | "points": false, 252 | "renderer": "flot", 253 | "seriesOverrides": [], 254 | "spaceLength": 10, 255 | "stack": false, 256 | "steppedLine": false, 257 | "targets": [ 258 | { 259 | "expr": "process_resident_memory_bytes", 260 | "interval": "", 261 | "legendFormat": "Memory Usage", 262 | "refId": "A" 263 | } 264 | ], 265 | "thresholds": [], 266 | "timeFrom": null, 267 | "timeRegions": [], 268 | "timeShift": null, 269 | "title": "Memory Usage", 270 | "tooltip": { 271 | "shared": true, 272 | "sort": 0, 273 | "value_type": "individual" 274 | }, 275 | "type": "graph", 276 | "xaxis": { 277 | "buckets": null, 278 | "mode": "time", 279 | "name": null, 280 | "show": true, 281 | "values": [] 282 | }, 283 | "yaxes": [ 284 | { 285 | "format": "bytes", 286 | "label": null, 287 | "logBase": 1, 288 | "max": null, 289 | "min": null, 290 | "show": true 291 | }, 292 | { 293 | "format": "short", 294 | "label": null, 295 | "logBase": 1, 296 | "max": null, 297 | "min": null, 298 | "show": true 299 | } 300 | ], 301 | "yaxis": { 302 | "align": false, 303 | "alignLevel": null 304 | } 305 | }, 306 | { 307 | "aliasColors": {}, 308 | "bars": false, 309 | "dashLength": 10, 310 | "dashes": false, 311 | "datasource": "Prometheus", 312 | "fieldConfig": { 313 | "defaults": { 314 | "custom": {} 315 | }, 316 | "overrides": [] 317 | }, 318 | "fill": 1, 319 | "fillGradient": 0, 320 | "gridPos": { 321 | "h": 8, 322 | "w": 12, 323 | "x": 12, 324 | "y": 8 325 | }, 326 | "hiddenSeries": false, 327 | "id": 8, 328 | "legend": { 329 | "avg": false, 330 | "current": false, 331 | "max": false, 332 | "min": false, 333 | "show": true, 334 | "total": false, 335 | "values": false 336 | }, 337 | "lines": true, 338 | "linewidth": 1, 339 | "nullPointMode": "null", 340 | "options": { 341 | "alertThreshold": true 342 | }, 343 | "percentage": false, 344 | "pluginVersion": "7.2.0", 345 | "pointradius": 2, 346 | "points": false, 347 | "renderer": "flot", 348 | "seriesOverrides": [], 349 | "spaceLength": 10, 350 | "stack": false, 351 | "steppedLine": false, 352 | "targets": [ 353 | { 354 | "expr": "process_cpu_usage", 355 | "interval": "", 356 | "legendFormat": "CPU Usage", 357 | "refId": "A" 358 | } 359 | ], 360 | "thresholds": [], 361 | "timeFrom": null, 362 | "timeRegions": [], 363 | "timeShift": null, 364 | "title": "CPU Usage", 365 | "tooltip": { 366 | "shared": true, 367 | "sort": 0, 368 | "value_type": "individual" 369 | }, 370 | "type": "graph", 371 | "xaxis": { 372 | "buckets": null, 373 | "mode": "time", 374 | "name": null, 375 | "show": true, 376 | "values": [] 377 | }, 378 | "yaxes": [ 379 | { 380 | "format": "percent", 381 | "label": null, 382 | "logBase": 1, 383 | "max": null, 384 | "min": null, 385 | "show": true 386 | }, 387 | { 388 | "format": "short", 389 | "label": null, 390 | "logBase": 1, 391 | "max": null, 392 | "min": null, 393 | "show": true 394 | } 395 | ], 396 | "yaxis": { 397 | "align": false, 398 | "alignLevel": null 399 | } 400 | } 401 | ], 402 | "schemaVersion": 25, 403 | "style": "dark", 404 | "tags": [], 405 | "templating": { 406 | "list": [] 407 | }, 408 | "time": { 409 | "from": "now-6h", 410 | "to": "now" 411 | }, 412 | "timepicker": {}, 413 | "timezone": "", 414 | "title": "FastAPI Python Application Dashboard", 415 | "uid": "python_fastapi_dashboard", 416 | "version": 1 417 | } 418 | -------------------------------------------------------------------------------- /prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | 4 | scrape_configs: 5 | - job_name: 'prometheus' 6 | static_configs: 7 | - targets: ['localhost:9090'] 8 | 9 | - job_name: 'fastapi-app' 10 | static_configs: 11 | - targets: ['fastapi-app:8000'] 12 | metrics_path: '/metrics' 13 | --------------------------------------------------------------------------------