├── README.md ├── grafana-dashboard-mysql ├── MySQL Server Dash Board.json └── MySQL Server DashBoard With Alert.json ├── person-app.yml ├── person-application ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── satish │ │ │ └── monitoring │ │ │ ├── PersonApplication.java │ │ │ ├── config │ │ │ └── SwaggerAPIDocumentationConfig.java │ │ │ ├── db │ │ │ ├── entities │ │ │ │ └── PersonEntity.java │ │ │ └── repositories │ │ │ │ └── PersonRepository.java │ │ │ ├── services │ │ │ ├── PersonService.java │ │ │ └── PersonServiceImpl.java │ │ │ └── web │ │ │ ├── models │ │ │ └── Person.java │ │ │ └── rest │ │ │ ├── PersonResource.java │ │ │ └── SwaggerUIController.java │ └── resources │ │ ├── application.properties │ │ └── db-scripts │ │ └── init-script.sql │ └── test │ └── java │ └── com │ └── satish │ └── monitoring │ └── PersonApplicationTests.java └── prometheus-mysql.yml /README.md: -------------------------------------------------------------------------------- 1 | # Monitoring 2 | To explore monitoring using Prometheus and Grafana. 3 | -------------------------------------------------------------------------------- /grafana-dashboard-mysql/MySQL Server Dash Board.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_PROMETHEUS-LOCAL", 5 | "label": "prometheus-local", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "5.0.0" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "5.0.0" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "prometheus", 28 | "name": "Prometheus", 29 | "version": "5.0.0" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "singlestat", 34 | "name": "Singlestat", 35 | "version": "5.0.0" 36 | } 37 | ], 38 | "annotations": { 39 | "list": [ 40 | { 41 | "builtIn": 1, 42 | "datasource": "-- Grafana --", 43 | "enable": true, 44 | "hide": true, 45 | "iconColor": "rgba(0, 211, 255, 1)", 46 | "name": "Annotations & Alerts", 47 | "type": "dashboard" 48 | } 49 | ] 50 | }, 51 | "editable": true, 52 | "gnetId": null, 53 | "graphTooltip": 0, 54 | "id": null, 55 | "links": [], 56 | "panels": [ 57 | { 58 | "aliasColors": {}, 59 | "bars": false, 60 | "dashLength": 10, 61 | "dashes": false, 62 | "datasource": "${DS_PROMETHEUS-LOCAL}", 63 | "description": "Count of All Queries run (select, insert, update, etc,)", 64 | "fill": 1, 65 | "gridPos": { 66 | "h": 7, 67 | "w": 24, 68 | "x": 0, 69 | "y": 0 70 | }, 71 | "id": 7, 72 | "legend": { 73 | "avg": false, 74 | "current": false, 75 | "max": false, 76 | "min": false, 77 | "show": true, 78 | "total": false, 79 | "values": false 80 | }, 81 | "lines": true, 82 | "linewidth": 1, 83 | "links": [], 84 | "nullPointMode": "null", 85 | "percentage": false, 86 | "pointradius": 5, 87 | "points": false, 88 | "renderer": "flot", 89 | "seriesOverrides": [], 90 | "spaceLength": 10, 91 | "stack": false, 92 | "steppedLine": false, 93 | "targets": [ 94 | { 95 | "expr": "irate(mysql_global_status_queries[1m])", 96 | "format": "time_series", 97 | "interval": "30s", 98 | "intervalFactor": 1, 99 | "legendFormat": "Queries Per Minute", 100 | "refId": "A" 101 | } 102 | ], 103 | "thresholds": [], 104 | "timeFrom": null, 105 | "timeShift": null, 106 | "title": "Total Queries Rate", 107 | "tooltip": { 108 | "shared": true, 109 | "sort": 0, 110 | "value_type": "individual" 111 | }, 112 | "type": "graph", 113 | "xaxis": { 114 | "buckets": null, 115 | "mode": "time", 116 | "name": null, 117 | "show": true, 118 | "values": [] 119 | }, 120 | "yaxes": [ 121 | { 122 | "decimals": 0, 123 | "format": "short", 124 | "label": null, 125 | "logBase": 1, 126 | "max": null, 127 | "min": "0", 128 | "show": true 129 | }, 130 | { 131 | "format": "short", 132 | "label": null, 133 | "logBase": 1, 134 | "max": null, 135 | "min": null, 136 | "show": false 137 | } 138 | ], 139 | "yaxis": { 140 | "align": false, 141 | "alignLevel": null 142 | } 143 | }, 144 | { 145 | "aliasColors": {}, 146 | "bars": false, 147 | "dashLength": 10, 148 | "dashes": false, 149 | "datasource": "${DS_PROMETHEUS-LOCAL}", 150 | "decimals": 0, 151 | "fill": 1, 152 | "gridPos": { 153 | "h": 7, 154 | "w": 9, 155 | "x": 0, 156 | "y": 7 157 | }, 158 | "id": 2, 159 | "legend": { 160 | "alignAsTable": true, 161 | "avg": false, 162 | "current": true, 163 | "hideEmpty": false, 164 | "hideZero": false, 165 | "max": true, 166 | "min": true, 167 | "rightSide": false, 168 | "show": true, 169 | "total": false, 170 | "values": true 171 | }, 172 | "lines": true, 173 | "linewidth": 2, 174 | "links": [], 175 | "nullPointMode": "null", 176 | "percentage": false, 177 | "pointradius": 5, 178 | "points": false, 179 | "renderer": "flot", 180 | "seriesOverrides": [], 181 | "spaceLength": 10, 182 | "stack": false, 183 | "steppedLine": false, 184 | "targets": [ 185 | { 186 | "expr": "mysql_global_status_threads_connected", 187 | "format": "time_series", 188 | "interval": "50s", 189 | "intervalFactor": 1, 190 | "legendFormat": "Active Connections", 191 | "refId": "A" 192 | }, 193 | { 194 | "expr": "mysql_global_status_max_used_connections", 195 | "format": "time_series", 196 | "interval": "", 197 | "intervalFactor": 1, 198 | "legendFormat": "Max Used Connections", 199 | "refId": "B" 200 | } 201 | ], 202 | "thresholds": [], 203 | "timeFrom": null, 204 | "timeShift": null, 205 | "title": "Connections", 206 | "tooltip": { 207 | "shared": true, 208 | "sort": 0, 209 | "value_type": "individual" 210 | }, 211 | "type": "graph", 212 | "xaxis": { 213 | "buckets": null, 214 | "mode": "time", 215 | "name": null, 216 | "show": true, 217 | "values": [] 218 | }, 219 | "yaxes": [ 220 | { 221 | "format": "short", 222 | "label": null, 223 | "logBase": 1, 224 | "max": null, 225 | "min": "0", 226 | "show": true 227 | }, 228 | { 229 | "format": "short", 230 | "label": null, 231 | "logBase": 1, 232 | "max": null, 233 | "min": "0", 234 | "show": true 235 | } 236 | ], 237 | "yaxis": { 238 | "align": false, 239 | "alignLevel": null 240 | } 241 | }, 242 | { 243 | "cacheTimeout": null, 244 | "colorBackground": false, 245 | "colorValue": true, 246 | "colors": [ 247 | "#629e51", 248 | "#7eb26d", 249 | "#ea6460" 250 | ], 251 | "datasource": "${DS_PROMETHEUS-LOCAL}", 252 | "description": "Display Current Active connections", 253 | "format": "none", 254 | "gauge": { 255 | "maxValue": 100, 256 | "minValue": 0, 257 | "show": true, 258 | "thresholdLabels": false, 259 | "thresholdMarkers": true 260 | }, 261 | "gridPos": { 262 | "h": 7, 263 | "w": 8, 264 | "x": 9, 265 | "y": 7 266 | }, 267 | "id": 4, 268 | "interval": null, 269 | "links": [], 270 | "mappingType": 1, 271 | "mappingTypes": [ 272 | { 273 | "name": "value to text", 274 | "value": 1 275 | }, 276 | { 277 | "name": "range to text", 278 | "value": 2 279 | } 280 | ], 281 | "maxDataPoints": 100, 282 | "nullPointMode": "connected", 283 | "nullText": null, 284 | "postfix": "", 285 | "postfixFontSize": "50%", 286 | "prefix": "", 287 | "prefixFontSize": "50%", 288 | "rangeMaps": [ 289 | { 290 | "from": "null", 291 | "text": "N/A", 292 | "to": "null" 293 | } 294 | ], 295 | "sparkline": { 296 | "fillColor": "rgba(31, 118, 189, 0.18)", 297 | "full": false, 298 | "lineColor": "rgb(238, 13, 47)", 299 | "show": true 300 | }, 301 | "tableColumn": "", 302 | "targets": [ 303 | { 304 | "expr": "mysql_global_status_threads_connected", 305 | "format": "time_series", 306 | "intervalFactor": 1, 307 | "legendFormat": "Active Connections", 308 | "refId": "A" 309 | } 310 | ], 311 | "thresholds": "", 312 | "title": "Active Connections", 313 | "transparent": true, 314 | "type": "singlestat", 315 | "valueFontSize": "80%", 316 | "valueMaps": [ 317 | { 318 | "op": "=", 319 | "text": "N/A", 320 | "value": "null" 321 | } 322 | ], 323 | "valueName": "min" 324 | }, 325 | { 326 | "cacheTimeout": null, 327 | "colorBackground": false, 328 | "colorValue": true, 329 | "colors": [ 330 | "#629e51", 331 | "#7eb26d", 332 | "#ea6460" 333 | ], 334 | "datasource": "${DS_PROMETHEUS-LOCAL}", 335 | "description": "Display Maximum Connections", 336 | "format": "none", 337 | "gauge": { 338 | "maxValue": 100, 339 | "minValue": 0, 340 | "show": true, 341 | "thresholdLabels": false, 342 | "thresholdMarkers": true 343 | }, 344 | "gridPos": { 345 | "h": 7, 346 | "w": 7, 347 | "x": 17, 348 | "y": 7 349 | }, 350 | "id": 5, 351 | "interval": null, 352 | "links": [], 353 | "mappingType": 1, 354 | "mappingTypes": [ 355 | { 356 | "name": "value to text", 357 | "value": 1 358 | }, 359 | { 360 | "name": "range to text", 361 | "value": 2 362 | } 363 | ], 364 | "maxDataPoints": 100, 365 | "nullPointMode": "connected", 366 | "nullText": null, 367 | "postfix": "", 368 | "postfixFontSize": "50%", 369 | "prefix": "", 370 | "prefixFontSize": "50%", 371 | "rangeMaps": [ 372 | { 373 | "from": "null", 374 | "text": "N/A", 375 | "to": "null" 376 | } 377 | ], 378 | "sparkline": { 379 | "fillColor": "rgba(31, 118, 189, 0.18)", 380 | "full": false, 381 | "lineColor": "rgb(238, 13, 47)", 382 | "show": true 383 | }, 384 | "tableColumn": "", 385 | "targets": [ 386 | { 387 | "expr": "mysql_global_status_max_used_connections", 388 | "format": "time_series", 389 | "intervalFactor": 1, 390 | "legendFormat": "Active Connections", 391 | "refId": "A" 392 | } 393 | ], 394 | "thresholds": "", 395 | "title": "Max Connections", 396 | "transparent": true, 397 | "type": "singlestat", 398 | "valueFontSize": "80%", 399 | "valueMaps": [ 400 | { 401 | "op": "=", 402 | "text": "N/A", 403 | "value": "null" 404 | } 405 | ], 406 | "valueName": "min" 407 | } 408 | ], 409 | "refresh": "5s", 410 | "schemaVersion": 16, 411 | "style": "dark", 412 | "tags": [], 413 | "templating": { 414 | "list": [] 415 | }, 416 | "time": { 417 | "from": "now-15m", 418 | "to": "now" 419 | }, 420 | "timepicker": { 421 | "refresh_intervals": [ 422 | "5s", 423 | "10s", 424 | "30s", 425 | "1m", 426 | "5m", 427 | "15m", 428 | "30m", 429 | "1h", 430 | "2h", 431 | "1d" 432 | ], 433 | "time_options": [ 434 | "5m", 435 | "15m", 436 | "1h", 437 | "6h", 438 | "12h", 439 | "24h", 440 | "2d", 441 | "7d", 442 | "30d" 443 | ] 444 | }, 445 | "timezone": "", 446 | "title": "MySQL Server Dash Board", 447 | "uid": "8SilaF4mk", 448 | "version": 5 449 | } -------------------------------------------------------------------------------- /grafana-dashboard-mysql/MySQL Server DashBoard With Alert.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_PROMETHEUS-LOCAL", 5 | "label": "prometheus-local", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "panel", 15 | "id": "alertlist", 16 | "name": "Alert List", 17 | "version": "5.0.0" 18 | }, 19 | { 20 | "type": "grafana", 21 | "id": "grafana", 22 | "name": "Grafana", 23 | "version": "5.0.0" 24 | }, 25 | { 26 | "type": "panel", 27 | "id": "graph", 28 | "name": "Graph", 29 | "version": "5.0.0" 30 | }, 31 | { 32 | "type": "datasource", 33 | "id": "prometheus", 34 | "name": "Prometheus", 35 | "version": "5.0.0" 36 | }, 37 | { 38 | "type": "panel", 39 | "id": "singlestat", 40 | "name": "Singlestat", 41 | "version": "5.0.0" 42 | } 43 | ], 44 | "annotations": { 45 | "list": [ 46 | { 47 | "builtIn": 1, 48 | "datasource": "-- Grafana --", 49 | "enable": true, 50 | "hide": true, 51 | "iconColor": "rgba(0, 211, 255, 1)", 52 | "name": "Annotations & Alerts", 53 | "type": "dashboard" 54 | } 55 | ] 56 | }, 57 | "editable": true, 58 | "gnetId": null, 59 | "graphTooltip": 0, 60 | "id": null, 61 | "links": [], 62 | "panels": [ 63 | { 64 | "aliasColors": {}, 65 | "bars": false, 66 | "dashLength": 10, 67 | "dashes": false, 68 | "datasource": "${DS_PROMETHEUS-LOCAL}", 69 | "description": "Count of All Queries run (select, insert, update, etc,)", 70 | "fill": 1, 71 | "gridPos": { 72 | "h": 7, 73 | "w": 11, 74 | "x": 0, 75 | "y": 0 76 | }, 77 | "id": 7, 78 | "legend": { 79 | "avg": false, 80 | "current": false, 81 | "max": false, 82 | "min": false, 83 | "show": true, 84 | "total": false, 85 | "values": false 86 | }, 87 | "lines": true, 88 | "linewidth": 1, 89 | "links": [], 90 | "nullPointMode": "null", 91 | "percentage": false, 92 | "pointradius": 5, 93 | "points": false, 94 | "renderer": "flot", 95 | "seriesOverrides": [], 96 | "spaceLength": 10, 97 | "stack": false, 98 | "steppedLine": false, 99 | "targets": [ 100 | { 101 | "expr": "irate(mysql_global_status_queries[1m])", 102 | "format": "time_series", 103 | "interval": "30s", 104 | "intervalFactor": 1, 105 | "legendFormat": "Queries Per Minute", 106 | "refId": "A" 107 | } 108 | ], 109 | "thresholds": [], 110 | "timeFrom": null, 111 | "timeShift": null, 112 | "title": "Total Queries Rate", 113 | "tooltip": { 114 | "shared": true, 115 | "sort": 0, 116 | "value_type": "individual" 117 | }, 118 | "type": "graph", 119 | "xaxis": { 120 | "buckets": null, 121 | "mode": "time", 122 | "name": null, 123 | "show": true, 124 | "values": [] 125 | }, 126 | "yaxes": [ 127 | { 128 | "decimals": 0, 129 | "format": "short", 130 | "label": null, 131 | "logBase": 1, 132 | "max": null, 133 | "min": "0", 134 | "show": true 135 | }, 136 | { 137 | "format": "short", 138 | "label": null, 139 | "logBase": 1, 140 | "max": null, 141 | "min": null, 142 | "show": false 143 | } 144 | ], 145 | "yaxis": { 146 | "align": false, 147 | "alignLevel": null 148 | } 149 | }, 150 | { 151 | "cacheTimeout": null, 152 | "colorBackground": false, 153 | "colorValue": true, 154 | "colors": [ 155 | "#629e51", 156 | "#7eb26d", 157 | "#ea6460" 158 | ], 159 | "datasource": "${DS_PROMETHEUS-LOCAL}", 160 | "description": "Display Current Active connections", 161 | "format": "none", 162 | "gauge": { 163 | "maxValue": 100, 164 | "minValue": 0, 165 | "show": true, 166 | "thresholdLabels": false, 167 | "thresholdMarkers": true 168 | }, 169 | "gridPos": { 170 | "h": 7, 171 | "w": 6, 172 | "x": 11, 173 | "y": 0 174 | }, 175 | "id": 4, 176 | "interval": null, 177 | "links": [], 178 | "mappingType": 1, 179 | "mappingTypes": [ 180 | { 181 | "name": "value to text", 182 | "value": 1 183 | }, 184 | { 185 | "name": "range to text", 186 | "value": 2 187 | } 188 | ], 189 | "maxDataPoints": 100, 190 | "nullPointMode": "connected", 191 | "nullText": null, 192 | "postfix": "", 193 | "postfixFontSize": "50%", 194 | "prefix": "", 195 | "prefixFontSize": "50%", 196 | "rangeMaps": [ 197 | { 198 | "from": "null", 199 | "text": "N/A", 200 | "to": "null" 201 | } 202 | ], 203 | "sparkline": { 204 | "fillColor": "rgba(31, 118, 189, 0.18)", 205 | "full": false, 206 | "lineColor": "rgb(238, 13, 47)", 207 | "show": true 208 | }, 209 | "tableColumn": "", 210 | "targets": [ 211 | { 212 | "expr": "mysql_global_status_threads_connected", 213 | "format": "time_series", 214 | "interval": "5s", 215 | "intervalFactor": 1, 216 | "legendFormat": "Active Connections", 217 | "refId": "A" 218 | } 219 | ], 220 | "thresholds": "", 221 | "title": "Active Connections", 222 | "transparent": true, 223 | "type": "singlestat", 224 | "valueFontSize": "80%", 225 | "valueMaps": [ 226 | { 227 | "op": "=", 228 | "text": "N/A", 229 | "value": "null" 230 | } 231 | ], 232 | "valueName": "min" 233 | }, 234 | { 235 | "cacheTimeout": null, 236 | "colorBackground": false, 237 | "colorValue": true, 238 | "colors": [ 239 | "#629e51", 240 | "#7eb26d", 241 | "#ea6460" 242 | ], 243 | "datasource": "${DS_PROMETHEUS-LOCAL}", 244 | "description": "Display Maximum Connections", 245 | "format": "none", 246 | "gauge": { 247 | "maxValue": 100, 248 | "minValue": 0, 249 | "show": true, 250 | "thresholdLabels": false, 251 | "thresholdMarkers": true 252 | }, 253 | "gridPos": { 254 | "h": 7, 255 | "w": 7, 256 | "x": 17, 257 | "y": 0 258 | }, 259 | "id": 5, 260 | "interval": null, 261 | "links": [], 262 | "mappingType": 1, 263 | "mappingTypes": [ 264 | { 265 | "name": "value to text", 266 | "value": 1 267 | }, 268 | { 269 | "name": "range to text", 270 | "value": 2 271 | } 272 | ], 273 | "maxDataPoints": 100, 274 | "nullPointMode": "connected", 275 | "nullText": null, 276 | "postfix": "", 277 | "postfixFontSize": "50%", 278 | "prefix": "", 279 | "prefixFontSize": "50%", 280 | "rangeMaps": [ 281 | { 282 | "from": "null", 283 | "text": "N/A", 284 | "to": "null" 285 | } 286 | ], 287 | "sparkline": { 288 | "fillColor": "rgba(31, 118, 189, 0.18)", 289 | "full": false, 290 | "lineColor": "rgb(238, 13, 47)", 291 | "show": true 292 | }, 293 | "tableColumn": "", 294 | "targets": [ 295 | { 296 | "expr": "mysql_global_status_max_used_connections", 297 | "format": "time_series", 298 | "intervalFactor": 1, 299 | "legendFormat": "Active Connections", 300 | "refId": "A" 301 | } 302 | ], 303 | "thresholds": "", 304 | "title": "Max Connections", 305 | "transparent": true, 306 | "type": "singlestat", 307 | "valueFontSize": "80%", 308 | "valueMaps": [ 309 | { 310 | "op": "=", 311 | "text": "N/A", 312 | "value": "null" 313 | } 314 | ], 315 | "valueName": "min" 316 | }, 317 | { 318 | "alert": { 319 | "conditions": [ 320 | { 321 | "evaluator": { 322 | "params": [ 323 | 2 324 | ], 325 | "type": "gt" 326 | }, 327 | "operator": { 328 | "type": "and" 329 | }, 330 | "query": { 331 | "params": [ 332 | "A", 333 | "5m", 334 | "now" 335 | ] 336 | }, 337 | "reducer": { 338 | "params": [], 339 | "type": "count" 340 | }, 341 | "type": "query" 342 | } 343 | ], 344 | "executionErrorState": "alerting", 345 | "frequency": "60s", 346 | "handler": 1, 347 | "message": "Threshold value breached", 348 | "name": "Connections alert", 349 | "noDataState": "no_data", 350 | "notifications": [ 351 | { 352 | "id": 2 353 | } 354 | ] 355 | }, 356 | "aliasColors": {}, 357 | "bars": false, 358 | "dashLength": 10, 359 | "dashes": false, 360 | "datasource": "${DS_PROMETHEUS-LOCAL}", 361 | "decimals": 0, 362 | "fill": 1, 363 | "gridPos": { 364 | "h": 7, 365 | "w": 17, 366 | "x": 0, 367 | "y": 7 368 | }, 369 | "id": 2, 370 | "legend": { 371 | "alignAsTable": true, 372 | "avg": false, 373 | "current": true, 374 | "hideEmpty": false, 375 | "hideZero": false, 376 | "max": true, 377 | "min": true, 378 | "rightSide": false, 379 | "show": true, 380 | "total": false, 381 | "values": true 382 | }, 383 | "lines": true, 384 | "linewidth": 2, 385 | "links": [], 386 | "nullPointMode": "null", 387 | "percentage": false, 388 | "pointradius": 5, 389 | "points": false, 390 | "renderer": "flot", 391 | "seriesOverrides": [], 392 | "spaceLength": 10, 393 | "stack": false, 394 | "steppedLine": false, 395 | "targets": [ 396 | { 397 | "expr": "mysql_global_status_threads_connected", 398 | "format": "time_series", 399 | "interval": "50s", 400 | "intervalFactor": 1, 401 | "legendFormat": "Active Connections", 402 | "refId": "A" 403 | }, 404 | { 405 | "expr": "mysql_global_status_max_used_connections", 406 | "format": "time_series", 407 | "interval": "", 408 | "intervalFactor": 1, 409 | "legendFormat": "Max Used Connections", 410 | "refId": "B" 411 | } 412 | ], 413 | "thresholds": [ 414 | { 415 | "colorMode": "critical", 416 | "fill": true, 417 | "line": true, 418 | "op": "gt", 419 | "value": 2 420 | } 421 | ], 422 | "timeFrom": null, 423 | "timeShift": null, 424 | "title": "Connections", 425 | "tooltip": { 426 | "shared": true, 427 | "sort": 0, 428 | "value_type": "individual" 429 | }, 430 | "type": "graph", 431 | "xaxis": { 432 | "buckets": null, 433 | "mode": "time", 434 | "name": null, 435 | "show": true, 436 | "values": [] 437 | }, 438 | "yaxes": [ 439 | { 440 | "format": "short", 441 | "label": null, 442 | "logBase": 1, 443 | "max": null, 444 | "min": "0", 445 | "show": true 446 | }, 447 | { 448 | "format": "short", 449 | "label": null, 450 | "logBase": 1, 451 | "max": null, 452 | "min": "0", 453 | "show": true 454 | } 455 | ], 456 | "yaxis": { 457 | "align": false, 458 | "alignLevel": null 459 | } 460 | }, 461 | { 462 | "gridPos": { 463 | "h": 7, 464 | "w": 6, 465 | "x": 17, 466 | "y": 7 467 | }, 468 | "id": 9, 469 | "limit": 10, 470 | "onlyAlertsOnDashboard": false, 471 | "show": "current", 472 | "sortOrder": 1, 473 | "stateFilter": [], 474 | "title": "Panel Title", 475 | "type": "alertlist" 476 | } 477 | ], 478 | "refresh": false, 479 | "schemaVersion": 16, 480 | "style": "dark", 481 | "tags": [], 482 | "templating": { 483 | "list": [] 484 | }, 485 | "time": { 486 | "from": "now-5m", 487 | "to": "now" 488 | }, 489 | "timepicker": { 490 | "refresh_intervals": [ 491 | "5s", 492 | "10s", 493 | "30s", 494 | "1m", 495 | "5m", 496 | "15m", 497 | "30m", 498 | "1h", 499 | "2h", 500 | "1d" 501 | ], 502 | "time_options": [ 503 | "5m", 504 | "15m", 505 | "1h", 506 | "6h", 507 | "12h", 508 | "24h", 509 | "2d", 510 | "7d", 511 | "30d" 512 | ] 513 | }, 514 | "timezone": "", 515 | "title": "MySQL Server Dash Board", 516 | "uid": "8SilaF4mk", 517 | "version": 39 518 | } -------------------------------------------------------------------------------- /person-app.yml: -------------------------------------------------------------------------------- 1 | #Global configurations 2 | global: 3 | scrape_interval: 5s # Set the scrape interval to every 5 seconds. 4 | evaluation_interval: 5s # Evaluate rules every 5 seconds. 5 | 6 | scrape_configs: 7 | - job_name: 'person-app' 8 | metrics_path: '/actuator/prometheus' 9 | static_configs: 10 | - targets: ['localhost:9000'] -------------------------------------------------------------------------------- /person-application/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### Log and H2 DB file ### 5 | /db/ 6 | /logs/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | /nbproject/private/ 25 | /build/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ -------------------------------------------------------------------------------- /person-application/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.satish.monitoring 7 | person-application 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | person-application 12 | Sample application to be monitored 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 2.5.0 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-actuator 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | true 41 | 42 | 43 | 44 | 45 | com.h2database 46 | h2 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-data-jpa 51 | 52 | 53 | 54 | 55 | io.micrometer 56 | micrometer-core 57 | 58 | 59 | io.micrometer 60 | micrometer-registry-prometheus 61 | 62 | 63 | 64 | 65 | io.springfox 66 | springfox-swagger2 67 | ${springfox-version} 68 | 69 | 70 | io.springfox 71 | springfox-swagger-ui 72 | ${springfox-version} 73 | 74 | 75 | 76 | com.fasterxml.jackson.core 77 | jackson-core 78 | 79 | 80 | com.fasterxml.jackson.datatype 81 | jackson-datatype-joda 82 | 83 | 84 | joda-time 85 | joda-time 86 | 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-starter-test 91 | test 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.springframework.boot 99 | spring-boot-maven-plugin 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/PersonApplication.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PersonApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PersonApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/config/SwaggerAPIDocumentationConfig.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.service.ApiInfo; 9 | import springfox.documentation.service.Contact; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | /** 15 | * 16 | * @author Satish Sharma 17 | * 18 | */ 19 | @EnableSwagger2 20 | @Configuration 21 | public class SwaggerAPIDocumentationConfig { 22 | 23 | ApiInfo apiInfo() { 24 | return new ApiInfoBuilder().title("Person REST CRUD operations API in Spring-Boot 2") 25 | .description( 26 | "Sample REST API for monitoring using Spring Boot, Prometheus and Graphana ") 27 | .termsOfServiceUrl("").version("0.0.1-SNAPSHOT").contact(new Contact("Satish Sharma", "https://github.com/hellosatish/monitoring/person", "https://github.com/hellosatish")).build(); 28 | } 29 | 30 | @Bean 31 | public Docket configureControllerPackageAndConvertors() { 32 | return new Docket(DocumentationType.SWAGGER_2).select() 33 | .apis(RequestHandlerSelectors.basePackage("org.spring")).build() 34 | .directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class) 35 | .directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class) 36 | .apiInfo(apiInfo()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/db/entities/PersonEntity.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.db.entities; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | 11 | import com.satish.monitoring.web.models.Person; 12 | 13 | import lombok.Data; 14 | import lombok.NoArgsConstructor; 15 | 16 | /** 17 | * 18 | * @author Satish Sharma 19 | *
20 |  *  	Entity class representing PERSON table in Database
21 |  *  For the sake of simplicity all fields are kept same as {@link Person} object to be used as DTO
22 |  * 
23 | */ 24 | @Data 25 | @Entity 26 | @Table(name = "PERSON") 27 | @NoArgsConstructor 28 | public class PersonEntity implements Serializable{ 29 | private static final long serialVersionUID = -8003246612943943723L; 30 | 31 | @Id 32 | @GeneratedValue(strategy= GenerationType.AUTO) 33 | private int personId; 34 | 35 | private String firstName; 36 | private String lastName; 37 | private String email; 38 | 39 | public PersonEntity( String firstName, String lastName, String email) { 40 | super(); 41 | this.firstName = firstName; 42 | this.lastName = lastName; 43 | this.email = email; 44 | } 45 | 46 | public PersonEntity(int personId, String firstName, String lastName, String email) { 47 | super(); 48 | this.personId = personId; 49 | this.firstName = firstName; 50 | this.lastName = lastName; 51 | this.email = email; 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/db/repositories/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.db.repositories; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import com.satish.monitoring.db.entities.PersonEntity; 7 | 8 | /** 9 | * 10 | * @author Satish Sharma 11 | *
12 |  *  	JPA repository interface for {@link PersonEntity} class
13 |  * 
14 | */ 15 | @Repository 16 | public interface PersonRepository extends JpaRepository{ 17 | 18 | } 19 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/services/PersonService.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.services; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import org.springframework.stereotype.Service; 7 | 8 | import com.satish.monitoring.web.models.Person; 9 | 10 | /** 11 | * 12 | * @author Satish Sharma 13 | * 14 | *
15 |  *  Service class for CRUD operation on person
16 |  * 
17 | */ 18 | @Service 19 | public interface PersonService { 20 | /** 21 | * 22 | * @param personId 23 | * @return {@link Optional} {@link Person} objects if present in database 24 | * for supplied person ID 25 | */ 26 | public Optional getPersonById(int personId); 27 | 28 | /** 29 | * 30 | * @return {@link List} of {@link Person} model class fo rall available 31 | * entities 32 | */ 33 | public List getAllPersons(); 34 | 35 | /** 36 | * 37 | * @param personId 38 | * @return Delete the person from database for supplied id 39 | */ 40 | public boolean removePerson(int personId); 41 | 42 | /** 43 | * 44 | * @param person 45 | * @return {@link Optional} {@link Person} objects after save or update Save 46 | * if no personId present else update 47 | */ 48 | public Optional saveUpdatePerson(Person person); 49 | } 50 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/services/PersonServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.services; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import com.satish.monitoring.db.entities.PersonEntity; 12 | import com.satish.monitoring.db.repositories.PersonRepository; 13 | import com.satish.monitoring.web.models.Person; 14 | 15 | /** 16 | * 17 | * @author Satish Sharma 18 | * 19 | *
20 |  *  Implementation class for {@link PersonService}
21 |  * 
22 | */ 23 | @Component 24 | public class PersonServiceImpl implements PersonService { 25 | 26 | private final PersonRepository personRepo; 27 | 28 | @Autowired 29 | PersonServiceImpl(PersonRepository personRepo) { 30 | this.personRepo = personRepo; 31 | } 32 | 33 | /** 34 | * Convert {@link Person} Object to {@link PersonEntity} object Set the 35 | * personId if present else return object with id null/0 36 | */ 37 | private final Function personToEntity = new Function() { 38 | @Override 39 | public PersonEntity apply(Person person) { 40 | if (person.getPersonId() == 0) { 41 | return new PersonEntity(person.getFirstName(), person.getLastName(), person.getEmail()); 42 | } else { 43 | return new PersonEntity(person.getPersonId(), person.getFirstName(), person.getLastName(), 44 | person.getEmail()); 45 | } 46 | } 47 | }; 48 | 49 | /** 50 | * Convert {@link PersonEntity} to {@link Person} object 51 | */ 52 | private final Function entityToPerson = new Function() { 53 | @Override 54 | public Person apply(PersonEntity entity) { 55 | return new Person(entity.getPersonId(), entity.getFirstName(), entity.getLastName(), entity.getEmail()); 56 | } 57 | }; 58 | 59 | 60 | /** 61 | * If record is present then convert the record else return the empty {@link Optional} 62 | */ 63 | @Override 64 | public Optional getPersonById(int personId) { 65 | return personRepo.findById(personId).map(s -> entityToPerson.apply(s)); 66 | } 67 | 68 | @Override 69 | public List getAllPersons() { 70 | return personRepo.findAll().parallelStream() 71 | .map(s -> entityToPerson.apply(s)) 72 | .collect(Collectors.toList()); 73 | } 74 | 75 | @Override 76 | public boolean removePerson(int personId) { 77 | personRepo.deleteById(personId); 78 | return true; 79 | } 80 | 81 | @Override 82 | public Optional saveUpdatePerson(Person person) { 83 | if(person.getPersonId() == 0 || personRepo.existsById(person.getPersonId())){ 84 | PersonEntity entity = personRepo.save(personToEntity.apply(person)); 85 | return Optional.of(entityToPerson.apply(entity)); 86 | }else{ 87 | return Optional.empty(); 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/web/models/Person.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.web.models; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.satish.monitoring.db.entities.PersonEntity; 6 | 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | /** 12 | * 13 | * @author Satish Sharma 14 | * 15 | *
16 |  *  Model class to represent a person;
17 |  *  For the sake of simplicity all fields are kept same as {@link PersonEntity} object to be used as Entity class representing th table
18 |  *  
19 | */ 20 | @Data 21 | @NoArgsConstructor 22 | @AllArgsConstructor 23 | public class Person implements Serializable { 24 | private static final long serialVersionUID = 3570556679061270028L; 25 | 26 | private int personId; 27 | private String firstName; 28 | private String lastName; 29 | private String email; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/web/rest/PersonResource.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.web.rest; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.DeleteMapping; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.PutMapping; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | import com.satish.monitoring.services.PersonService; 18 | import com.satish.monitoring.web.models.Person; 19 | 20 | /** 21 | * 22 | * @author Satish Sharma 23 | * 24 | *
 25 |  *  Controller to handle CRUD operations
 26 |  * 
27 | */ 28 | @RestController 29 | @RequestMapping("/person") 30 | public class PersonResource { 31 | 32 | private final PersonService personService; 33 | /** 34 | * Constructor to autowire PersonService instance. 35 | * Look we have declared personService as final without initialization 36 | */ 37 | @Autowired 38 | PersonResource(PersonService personService) { 39 | this.personService = personService; 40 | } 41 | 42 | /** 43 | * 44 | * @return expose GET endpoint to return {@link List} of all available persons 45 | */ 46 | @GetMapping 47 | public List getAllPerson() { 48 | return personService.getAllPersons(); 49 | } 50 | 51 | /** 52 | * 53 | * @param personId supplied as path variable 54 | * @return expose GET endpoint to return {@link Person} for the supplied person id 55 | * return HTTP 404 in case person is not found in database 56 | */ 57 | @GetMapping(value = "/{personId}") 58 | public ResponseEntity getPerson(@PathVariable("personId") int personId) { 59 | return personService.getPersonById(personId).map(person -> { 60 | return ResponseEntity.ok(person); 61 | }).orElseGet(() -> { 62 | return new ResponseEntity(HttpStatus.NOT_FOUND); 63 | }); 64 | } 65 | 66 | /** 67 | * 68 | * @param person JSON body 69 | * @return expose POST mapping and return newly created person in case of successful operation 70 | * return HTTP 417 in case of failure 71 | */ 72 | @PostMapping 73 | public ResponseEntity addNewPerson(@RequestBody Person person) { 74 | return personService.saveUpdatePerson(person).map(p -> { 75 | return ResponseEntity.ok(p); 76 | }).orElseGet(() -> { 77 | return new ResponseEntity(HttpStatus.EXPECTATION_FAILED); 78 | }); 79 | } 80 | 81 | /** 82 | * 83 | * @param person JSON body 84 | * @return expose PUT mapping and return newly created or updated person in case of successful operation 85 | * return HTTP 417 in case of failure 86 | * 87 | */ 88 | @PutMapping 89 | public ResponseEntity updatePerson(@RequestBody Person person) { 90 | return personService.saveUpdatePerson(person).map(p -> { 91 | return ResponseEntity.ok(p); 92 | }).orElseGet(() -> { 93 | return new ResponseEntity(HttpStatus.EXPECTATION_FAILED); 94 | }); 95 | } 96 | /** 97 | * 98 | * @param personId person id to be deleted 99 | * @return expose DELETE mapping and return success message if operation was successful. 100 | * return HTTP 417 in case of failure 101 | * 102 | */ 103 | @DeleteMapping(value = "/{personId}") 104 | public ResponseEntity deletePerson(@PathVariable("personId") int personId) { 105 | if (personService.removePerson(personId)) { 106 | return ResponseEntity.ok("Person with id : " + personId + " removed"); 107 | } else { 108 | return new ResponseEntity("Error deleting enitty ", HttpStatus.EXPECTATION_FAILED); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /person-application/src/main/java/com/satish/monitoring/web/rest/SwaggerUIController.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring.web.rest; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | /** 7 | * 8 | * @author satish-s 9 | *
10 |  *  Controller to redirect request to swagger-ui page
11 |  * 
12 | */ 13 | @Controller 14 | public class SwaggerUIController { 15 | 16 | @RequestMapping(value = "/") 17 | public String index() { 18 | return "redirect:swagger-ui.html"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /person-application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Server configurations. 2 | server.port=9000 3 | logging.level.com.satish.monitoring=debug 4 | logging.file=logs/monitoring.log 5 | 6 | # Database configurations. 7 | spring.datasource.driver-class-name=org.h2.Driver 8 | spring.datasource.url=jdbc:h2:file:./db/target/person_db;DB_CLOSE_DELAY=-1 9 | spring.datasource.username=satish 10 | spring.datasource.data=classpath:/db-scripts/init-script.sql 11 | 12 | spring.h2.console.enabled=true 13 | spring.h2.console.path=/db-console 14 | 15 | spring.jpa.show-sql=true 16 | # change the below to none in production 17 | spring.jpa.hibernate.ddl-auto=create-drop 18 | 19 | #Metrics related configurations 20 | management.endpoint.metrics.enabled=true 21 | management.endpoints.web.exposure.include=* 22 | management.endpoint.prometheus.enabled=true 23 | management.metrics.export.prometheus.enabled=true 24 | -------------------------------------------------------------------------------- /person-application/src/main/resources/db-scripts/init-script.sql: -------------------------------------------------------------------------------- 1 | insert into PERSON (PERSON_ID,FIRST_NAME,LAST_NAME,EMAIL) values 2 | (1, 'Satish','Sharma','myid@company.com'), 3 | (2, 'Gaurav','Gupta','myid@company.com'), 4 | (3, 'Ashutosh','Chandrawat','myid@company.com') 5 | ; -------------------------------------------------------------------------------- /person-application/src/test/java/com/satish/monitoring/PersonApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.satish.monitoring; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class PersonApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /prometheus-mysql.yml: -------------------------------------------------------------------------------- 1 | # config file for monitoring MySQL via mysqld_exporter on localhost 2 | global: 3 | scrape_interval: 5s # Set the scrape interval to every 15 seconds. Default is every 1 minute. 4 | evaluation_interval: 5s # Evaluate rules every 15 seconds. The default is every 1 minute. 5 | 6 | scrape_configs: 7 | - job_name: 'mysql-monitor' 8 | static_configs: 9 | - targets: ['localhost:9104'] 10 | labels: 11 | alias: db1 12 | params: 13 | collect[]: 14 | - perf_schema.tableiowaits 15 | - perf_schema.indexiowaits 16 | - perf_schema.tablelocks --------------------------------------------------------------------------------