diff --git a/MONITORING_GUIDE.md b/MONITORING_GUIDE.md index 0ee6502..88bd54f 100644 --- a/MONITORING_GUIDE.md +++ b/MONITORING_GUIDE.md @@ -2,14 +2,31 @@ ## Быстрый старт -1. **Доступ к сервисам:** +1. **Запуск:** + ```bash + docker compose up -d + ``` + +2. **Доступ к сервисам:** - Приложение: http://localhost:8080 - Prometheus: http://localhost:9090 - - Grafana: http://localhost:3000 (admin/admin) + - Grafana: http://localhost:3000 (логин: admin, пароль: admin) -2. **Дашборды автоматически загружены:** - - Spring Boot Application Metrics - - PostgreSQL & HikariCP Monitoring +3. **Дашборды:** + - Открой Grafana → Home → Dashboards + - Два дашборда загружены автоматически: + - **Spring Boot Application Metrics** — HTTP, JVM, CPU, GC + - **PostgreSQL & HikariCP Monitoring** — connection pool, база данных + +4. **Создай нагрузку для проверки:** + ```bash + # Создать задачу + curl -X POST http://localhost:8080/api/tasks \ + -H "Content-Type: application/json" \ + -d '{"title":"Test","description":"Load test","completed":false}' + + # Посмотреть метрики появятся в Grafana через 5-15 секунд + ``` ## Основные метрики diff --git a/grafana-dashboard-app.json b/grafana-dashboard-app.json index 6bc8fe9..bcf7829 100644 --- a/grafana-dashboard-app.json +++ b/grafana-dashboard-app.json @@ -1,195 +1,230 @@ { - "dashboard": { - "title": "Spring Boot Application Metrics", - "tags": ["spring-boot", "todo-app"], - "timezone": "browser", - "panels": [ - { - "id": 1, - "title": "HTTP Request Rate", - "type": "graph", - "gridPos": {"x": 0, "y": 0, "w": 12, "h": 8}, - "targets": [ - { - "expr": "rate(http_server_requests_seconds_count{application=\"todo\"}[1m])", - "legendFormat": "{{method}} {{uri}} - {{status}}" - } - ], - "yaxes": [ - {"format": "reqps", "label": "Requests/sec"}, - {"format": "short"} - ] - }, - { - "id": 2, - "title": "HTTP Request Duration (p95, p99)", - "type": "graph", - "gridPos": {"x": 12, "y": 0, "w": 12, "h": 8}, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application=\"todo\"}[5m])) by (le, uri))", - "legendFormat": "p95 - {{uri}}" - }, - { - "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{application=\"todo\"}[5m])) by (le, uri))", - "legendFormat": "p99 - {{uri}}" - } - ], - "yaxes": [ - {"format": "s", "label": "Duration"}, - {"format": "short"} - ] - }, - { - "id": 3, - "title": "HTTP Status Codes", - "type": "graph", - "gridPos": {"x": 0, "y": 8, "w": 12, "h": 8}, - "targets": [ - { - "expr": "sum(rate(http_server_requests_seconds_count{application=\"todo\"}[1m])) by (status)", - "legendFormat": "{{status}}" - } - ], - "yaxes": [ - {"format": "reqps"}, - {"format": "short"} - ] - }, - { - "id": 4, - "title": "JVM Memory Used", - "type": "graph", - "gridPos": {"x": 12, "y": 8, "w": 12, "h": 8}, - "targets": [ - { - "expr": "jvm_memory_used_bytes{application=\"todo\", area=\"heap\"}", - "legendFormat": "Heap" - }, - { - "expr": "jvm_memory_used_bytes{application=\"todo\", area=\"nonheap\"}", - "legendFormat": "Non-Heap" - }, - { - "expr": "jvm_memory_max_bytes{application=\"todo\", area=\"heap\"}", - "legendFormat": "Heap Max" - } - ], - "yaxes": [ - {"format": "bytes"}, - {"format": "short"} - ] - }, - { - "id": 5, - "title": "Database Connection Pool", - "type": "graph", - "gridPos": {"x": 0, "y": 16, "w": 12, "h": 8}, - "targets": [ - { - "expr": "hikaricp_connections_active{application=\"todo\"}", - "legendFormat": "Active" - }, - { - "expr": "hikaricp_connections_idle{application=\"todo\"}", - "legendFormat": "Idle" - }, - { - "expr": "hikaricp_connections{application=\"todo\"}", - "legendFormat": "Total" - }, - { - "expr": "hikaricp_connections_max{application=\"todo\"}", - "legendFormat": "Max" - } - ], - "yaxes": [ - {"format": "short", "label": "Connections"}, - {"format": "short"} - ] - }, - { - "id": 6, - "title": "Database Connection Acquire Time", - "type": "graph", - "gridPos": {"x": 12, "y": 16, "w": 12, "h": 8}, - "targets": [ - { - "expr": "rate(hikaricp_connections_acquire_seconds_sum{application=\"todo\"}[1m]) / rate(hikaricp_connections_acquire_seconds_count{application=\"todo\"}[1m])", - "legendFormat": "Avg Acquire Time" - } - ], - "yaxes": [ - {"format": "s"}, - {"format": "short"} - ] - }, - { - "id": 7, - "title": "JVM Threads", - "type": "graph", - "gridPos": {"x": 0, "y": 24, "w": 8, "h": 8}, - "targets": [ - { - "expr": "jvm_threads_live_threads{application=\"todo\"}", - "legendFormat": "Live" - }, - { - "expr": "jvm_threads_daemon_threads{application=\"todo\"}", - "legendFormat": "Daemon" - }, - { - "expr": "jvm_threads_peak_threads{application=\"todo\"}", - "legendFormat": "Peak" - } - ], - "yaxes": [ - {"format": "short", "label": "Threads"}, - {"format": "short"} - ] - }, - { - "id": 8, - "title": "GC Pause Time", - "type": "graph", - "gridPos": {"x": 8, "y": 24, "w": 8, "h": 8}, - "targets": [ - { - "expr": "rate(jvm_gc_pause_seconds_sum{application=\"todo\"}[1m])", - "legendFormat": "{{action}} - {{cause}}" - } - ], - "yaxes": [ - {"format": "s", "label": "GC Time"}, - {"format": "short"} - ] - }, - { - "id": 9, - "title": "System CPU Usage", - "type": "graph", - "gridPos": {"x": 16, "y": 24, "w": 8, "h": 8}, - "targets": [ - { - "expr": "system_cpu_usage{application=\"todo\"}", - "legendFormat": "System" - }, - { - "expr": "process_cpu_usage{application=\"todo\"}", - "legendFormat": "Process" - } - ], - "yaxes": [ - {"format": "percentunit", "label": "CPU"}, - {"format": "short"} - ] + "title": "Spring Boot Application Metrics", + "tags": ["spring-boot", "todo-app"], + "timezone": "browser", + "schemaVersion": 16, + "version": 0, + "refresh": "5s", + "panels": [ + { + "id": 1, + "title": "HTTP Request Rate", + "type": "timeseries", + "gridPos": {"x": 0, "y": 0, "w": 12, "h": 8}, + "targets": [ + { + "expr": "rate(http_server_requests_seconds_count{application=\"todo\"}[1m])", + "legendFormat": "{{method}} {{uri}} - {{status}}", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "reqps", + "custom": {} + } + } + }, + { + "id": 2, + "title": "HTTP Request Duration (p95, p99)", + "type": "timeseries", + "gridPos": {"x": 12, "y": 0, "w": 12, "h": 8}, + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application=\"todo\"}[5m])) by (le, uri))", + "legendFormat": "p95 - {{uri}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{application=\"todo\"}[5m])) by (le, uri))", + "legendFormat": "p99 - {{uri}}", + "refId": "B" + } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": {} + } + } + }, + { + "id": 3, + "title": "HTTP Status Codes", + "type": "timeseries", + "gridPos": {"x": 0, "y": 8, "w": 12, "h": 8}, + "targets": [ + { + "expr": "sum(rate(http_server_requests_seconds_count{application=\"todo\"}[1m])) by (status)", + "legendFormat": "{{status}}", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "reqps", + "custom": {} + } + } + }, + { + "id": 4, + "title": "JVM Memory Used", + "type": "timeseries", + "gridPos": {"x": 12, "y": 8, "w": 12, "h": 8}, + "targets": [ + { + "expr": "jvm_memory_used_bytes{application=\"todo\", area=\"heap\"}", + "legendFormat": "Heap", + "refId": "A" + }, + { + "expr": "jvm_memory_used_bytes{application=\"todo\", area=\"nonheap\"}", + "legendFormat": "Non-Heap", + "refId": "B" + }, + { + "expr": "jvm_memory_max_bytes{application=\"todo\", area=\"heap\"}", + "legendFormat": "Heap Max", + "refId": "C" + } + ], + "fieldConfig": { + "defaults": { + "unit": "bytes", + "custom": {} + } + } + }, + { + "id": 5, + "title": "Database Connection Pool", + "type": "timeseries", + "gridPos": {"x": 0, "y": 16, "w": 12, "h": 8}, + "targets": [ + { + "expr": "hikaricp_connections_active{application=\"todo\"}", + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "hikaricp_connections_idle{application=\"todo\"}", + "legendFormat": "Idle", + "refId": "B" + }, + { + "expr": "hikaricp_connections{application=\"todo\"}", + "legendFormat": "Total", + "refId": "C" + }, + { + "expr": "hikaricp_connections_max{application=\"todo\"}", + "legendFormat": "Max", + "refId": "D" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": {} + } + } + }, + { + "id": 6, + "title": "Database Connection Acquire Time", + "type": "timeseries", + "gridPos": {"x": 12, "y": 16, "w": 12, "h": 8}, + "targets": [ + { + "expr": "rate(hikaricp_connections_acquire_seconds_sum{application=\"todo\"}[1m]) / rate(hikaricp_connections_acquire_seconds_count{application=\"todo\"}[1m])", + "legendFormat": "Avg Acquire Time", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": {} + } + } + }, + { + "id": 7, + "title": "JVM Threads", + "type": "timeseries", + "gridPos": {"x": 0, "y": 24, "w": 8, "h": 8}, + "targets": [ + { + "expr": "jvm_threads_live_threads{application=\"todo\"}", + "legendFormat": "Live", + "refId": "A" + }, + { + "expr": "jvm_threads_daemon_threads{application=\"todo\"}", + "legendFormat": "Daemon", + "refId": "B" + }, + { + "expr": "jvm_threads_peak_threads{application=\"todo\"}", + "legendFormat": "Peak", + "refId": "C" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": {} + } + } + }, + { + "id": 8, + "title": "GC Pause Time", + "type": "timeseries", + "gridPos": {"x": 8, "y": 24, "w": 8, "h": 8}, + "targets": [ + { + "expr": "rate(jvm_gc_pause_seconds_sum{application=\"todo\"}[1m])", + "legendFormat": "{{action}} - {{cause}}", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": {} + } + } + }, + { + "id": 9, + "title": "System CPU Usage", + "type": "timeseries", + "gridPos": {"x": 16, "y": 24, "w": 8, "h": 8}, + "targets": [ + { + "expr": "system_cpu_usage{application=\"todo\"}", + "legendFormat": "System", + "refId": "A" + }, + { + "expr": "process_cpu_usage{application=\"todo\"}", + "legendFormat": "Process", + "refId": "B" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "custom": {} + } } - ], - "refresh": "5s", - "time": { - "from": "now-15m", - "to": "now" } - }, - "overwrite": true + ], + "time": { + "from": "now-15m", + "to": "now" + } } diff --git a/grafana-dashboard-db.json b/grafana-dashboard-db.json index aafb3b5..b5beb39 100644 --- a/grafana-dashboard-db.json +++ b/grafana-dashboard-db.json @@ -1,187 +1,233 @@ { - "dashboard": { - "title": "PostgreSQL & HikariCP Monitoring", - "tags": ["database", "postgres", "hikaricp"], - "timezone": "browser", - "panels": [ - { - "id": 1, - "title": "Connection Pool Status", - "type": "stat", - "gridPos": {"x": 0, "y": 0, "w": 6, "h": 4}, - "targets": [ - { - "expr": "hikaricp_connections_active{application=\"todo\"}", - "legendFormat": "Active" - } - ], - "options": { - "colorMode": "value", - "graphMode": "area" + "title": "PostgreSQL & HikariCP Monitoring", + "tags": ["database", "postgres", "hikaricp"], + "timezone": "browser", + "schemaVersion": 16, + "version": 0, + "refresh": "5s", + "panels": [ + { + "id": 1, + "title": "Connection Pool Status - Active", + "type": "stat", + "gridPos": {"x": 0, "y": 0, "w": 6, "h": 4}, + "targets": [ + { + "expr": "hikaricp_connections_active{application=\"todo\"}", + "legendFormat": "Active", + "refId": "A" } + ], + "options": { + "colorMode": "value", + "graphMode": "area" }, - { - "id": 2, - "title": "Idle Connections", - "type": "stat", - "gridPos": {"x": 6, "y": 0, "w": 6, "h": 4}, - "targets": [ - { - "expr": "hikaricp_connections_idle{application=\"todo\"}", - "legendFormat": "Idle" - } - ], - "options": { - "colorMode": "value", - "graphMode": "area" + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + }, + { + "id": 2, + "title": "Idle Connections", + "type": "stat", + "gridPos": {"x": 6, "y": 0, "w": 6, "h": 4}, + "targets": [ + { + "expr": "hikaricp_connections_idle{application=\"todo\"}", + "legendFormat": "Idle", + "refId": "A" + } + ], + "options": { + "colorMode": "value", + "graphMode": "area" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + }, + { + "id": 3, + "title": "Total Connections", + "type": "stat", + "gridPos": {"x": 12, "y": 0, "w": 6, "h": 4}, + "targets": [ + { + "expr": "hikaricp_connections{application=\"todo\"}", + "legendFormat": "Total", + "refId": "A" + } + ], + "options": { + "colorMode": "value", + "graphMode": "area" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + }, + { + "id": 4, + "title": "Pending Threads", + "type": "stat", + "gridPos": {"x": 18, "y": 0, "w": 6, "h": 4}, + "targets": [ + { + "expr": "hikaricp_connections_pending{application=\"todo\"}", + "legendFormat": "Pending", + "refId": "A" + } + ], + "options": { + "colorMode": "value", + "graphMode": "area" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + } + } + }, + { + "id": 5, + "title": "Connection Pool Utilization (%)", + "type": "timeseries", + "gridPos": {"x": 0, "y": 4, "w": 12, "h": 8}, + "targets": [ + { + "expr": "(hikaricp_connections_active{application=\"todo\"} / hikaricp_connections_max{application=\"todo\"}) * 100", + "legendFormat": "Active %", + "refId": "A" + }, + { + "expr": "(hikaricp_connections{application=\"todo\"} / hikaricp_connections_max{application=\"todo\"}) * 100", + "legendFormat": "Total %", + "refId": "B" + } + ], + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": {} + } + } + }, + { + "id": 6, + "title": "Connection Acquire Time", + "type": "timeseries", + "gridPos": {"x": 12, "y": 4, "w": 12, "h": 8}, + "targets": [ + { + "expr": "histogram_quantile(0.5, rate(hikaricp_connections_acquire_seconds_bucket{application=\"todo\"}[1m]))", + "legendFormat": "p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, rate(hikaricp_connections_acquire_seconds_bucket{application=\"todo\"}[1m]))", + "legendFormat": "p95", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, rate(hikaricp_connections_acquire_seconds_bucket{application=\"todo\"}[1m]))", + "legendFormat": "p99", + "refId": "C" + } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": {} + } + } + }, + { + "id": 7, + "title": "Connection Timeout Count", + "type": "timeseries", + "gridPos": {"x": 0, "y": 12, "w": 12, "h": 8}, + "targets": [ + { + "expr": "rate(hikaricp_connections_timeout_total{application=\"todo\"}[1m])", + "legendFormat": "Timeouts/sec", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": {} + } + } + }, + { + "id": 8, + "title": "Connection Creation Time", + "type": "timeseries", + "gridPos": {"x": 12, "y": 12, "w": 12, "h": 8}, + "targets": [ + { + "expr": "rate(hikaricp_connections_creation_seconds_sum{application=\"todo\"}[1m]) / rate(hikaricp_connections_creation_seconds_count{application=\"todo\"}[1m])", + "legendFormat": "Avg Creation Time", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": {} + } + } + }, + { + "id": 9, + "title": "Connection Usage Time", + "type": "timeseries", + "gridPos": {"x": 0, "y": 20, "w": 12, "h": 8}, + "targets": [ + { + "expr": "rate(hikaricp_connections_usage_seconds_sum{application=\"todo\"}[1m]) / rate(hikaricp_connections_usage_seconds_count{application=\"todo\"}[1m])", + "legendFormat": "Avg Usage Time", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": {} + } + } + }, + { + "id": 10, + "title": "Active Connections Timeline", + "type": "timeseries", + "gridPos": {"x": 12, "y": 20, "w": 12, "h": 8}, + "targets": [ + { + "expr": "hikaricp_connections_active{application=\"todo\"}", + "legendFormat": "Active Connections", + "refId": "A" + } + ], + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": {} } - }, - { - "id": 3, - "title": "Total Connections", - "type": "stat", - "gridPos": {"x": 12, "y": 0, "w": 6, "h": 4}, - "targets": [ - { - "expr": "hikaricp_connections{application=\"todo\"}", - "legendFormat": "Total" - } - ], - "options": { - "colorMode": "value", - "graphMode": "area" - } - }, - { - "id": 4, - "title": "Pending Threads", - "type": "stat", - "gridPos": {"x": 18, "y": 0, "w": 6, "h": 4}, - "targets": [ - { - "expr": "hikaricp_connections_pending{application=\"todo\"}", - "legendFormat": "Pending" - } - ], - "options": { - "colorMode": "value", - "graphMode": "area" - } - }, - { - "id": 5, - "title": "Connection Pool Utilization (%)", - "type": "graph", - "gridPos": {"x": 0, "y": 4, "w": 12, "h": 8}, - "targets": [ - { - "expr": "(hikaricp_connections_active{application=\"todo\"} / hikaricp_connections_max{application=\"todo\"}) * 100", - "legendFormat": "Active %" - }, - { - "expr": "(hikaricp_connections{application=\"todo\"} / hikaricp_connections_max{application=\"todo\"}) * 100", - "legendFormat": "Total %" - } - ], - "yaxes": [ - {"format": "percent", "label": "Utilization", "min": 0, "max": 100}, - {"format": "short"} - ] - }, - { - "id": 6, - "title": "Connection Acquire Time", - "type": "graph", - "gridPos": {"x": 12, "y": 4, "w": 12, "h": 8}, - "targets": [ - { - "expr": "histogram_quantile(0.5, rate(hikaricp_connections_acquire_seconds_bucket{application=\"todo\"}[1m]))", - "legendFormat": "p50" - }, - { - "expr": "histogram_quantile(0.95, rate(hikaricp_connections_acquire_seconds_bucket{application=\"todo\"}[1m]))", - "legendFormat": "p95" - }, - { - "expr": "histogram_quantile(0.99, rate(hikaricp_connections_acquire_seconds_bucket{application=\"todo\"}[1m]))", - "legendFormat": "p99" - } - ], - "yaxes": [ - {"format": "s", "label": "Time"}, - {"format": "short"} - ] - }, - { - "id": 7, - "title": "Connection Timeout Count", - "type": "graph", - "gridPos": {"x": 0, "y": 12, "w": 12, "h": 8}, - "targets": [ - { - "expr": "rate(hikaricp_connections_timeout_total{application=\"todo\"}[1m])", - "legendFormat": "Timeouts/sec" - } - ], - "yaxes": [ - {"format": "short"}, - {"format": "short"} - ] - }, - { - "id": 8, - "title": "Connection Creation Time", - "type": "graph", - "gridPos": {"x": 12, "y": 12, "w": 12, "h": 8}, - "targets": [ - { - "expr": "rate(hikaricp_connections_creation_seconds_sum{application=\"todo\"}[1m]) / rate(hikaricp_connections_creation_seconds_count{application=\"todo\"}[1m])", - "legendFormat": "Avg Creation Time" - } - ], - "yaxes": [ - {"format": "s"}, - {"format": "short"} - ] - }, - { - "id": 9, - "title": "Connection Usage Time", - "type": "graph", - "gridPos": {"x": 0, "y": 20, "w": 12, "h": 8}, - "targets": [ - { - "expr": "rate(hikaricp_connections_usage_seconds_sum{application=\"todo\"}[1m]) / rate(hikaricp_connections_usage_seconds_count{application=\"todo\"}[1m])", - "legendFormat": "Avg Usage Time" - } - ], - "yaxes": [ - {"format": "s"}, - {"format": "short"} - ] - }, - { - "id": 10, - "title": "JDBC Queries Rate", - "type": "graph", - "gridPos": {"x": 12, "y": 20, "w": 12, "h": 8}, - "targets": [ - { - "expr": "rate(jdbc_connections_active{application=\"todo\"}[1m])", - "legendFormat": "Active JDBC Connections" - } - ], - "yaxes": [ - {"format": "short"}, - {"format": "short"} - ] } - ], - "refresh": "5s", - "time": { - "from": "now-15m", - "to": "now" } - }, - "overwrite": true + ], + "time": { + "from": "now-15m", + "to": "now" + } }