|
| 1 | +{ |
| 2 | + "title": "Armeria xDS Metrics", |
| 3 | + "uid": "armeria-xds", |
| 4 | + "editable": true, |
| 5 | + "time": {"from": "now-5m", "to": "now"}, |
| 6 | + "refresh": "1s", |
| 7 | + "timepicker": {"refresh_intervals": ["1s", "2s", "5s", "10s", "30s"]}, |
| 8 | + "templating": { |
| 9 | + "list": [ |
| 10 | + { |
| 11 | + "name": "cluster", |
| 12 | + "type": "query", |
| 13 | + "query": "label_values(armeria_xds_lb_membership, cluster)", |
| 14 | + "datasource": "Prometheus", |
| 15 | + "refresh": 2, |
| 16 | + "includeAll": true, |
| 17 | + "multi": true, |
| 18 | + "current": {"text": "All", "value": "$__all"} |
| 19 | + } |
| 20 | + ] |
| 21 | + }, |
| 22 | + "panels": [ |
| 23 | + {"title": "Armeria", "type": "row", "gridPos": {"h": 1, "w": 24, "x": 0, "y": 0}, "collapsed": false}, |
| 24 | + { |
| 25 | + "title": "L1 Requests (by status)", |
| 26 | + "description": "Per-attempt counts (includes retry attempts)", |
| 27 | + "type": "timeseries", |
| 28 | + "gridPos": {"h": 6, "w": 8, "x": 0, "y": 1}, |
| 29 | + "interval": "1s", |
| 30 | + "targets": [{"expr": "sum by (http_status)(rate(layer1_requests_total[3s]))", "legendFormat": "{{http_status}}"}], |
| 31 | + "fieldConfig": {"defaults": {"unit": "reqps"}} |
| 32 | + }, |
| 33 | + { |
| 34 | + "title": "L2 Requests (by status)", |
| 35 | + "description": "Aggregate Layer 2 server requests from Layer 1", |
| 36 | + "type": "timeseries", |
| 37 | + "gridPos": {"h": 6, "w": 8, "x": 8, "y": 1}, |
| 38 | + "interval": "1s", |
| 39 | + "targets": [{"expr": "sum by (http_status)(rate(layer2_requests_total{side=\"server\"}[3s]))", "legendFormat": "{{http_status}}"}], |
| 40 | + "fieldConfig": {"defaults": {"unit": "reqps"}} |
| 41 | + }, |
| 42 | + { |
| 43 | + "title": "Retries", |
| 44 | + "description": "Rate of retry attempts (actual requests minus logical requests)", |
| 45 | + "type": "timeseries", |
| 46 | + "gridPos": {"h": 6, "w": 8, "x": 16, "y": 1}, |
| 47 | + "interval": "1s", |
| 48 | + "targets": [ |
| 49 | + {"expr": "sum(rate(layer1_actual_requests_attempts_sum[3s])) - sum(rate(layer1_actual_requests_attempts_count[3s]))", "legendFormat": "L1 retries"}, |
| 50 | + { |
| 51 | + "expr": "sum(rate(layer2_actual_requests_attempts_sum{side=\"client\"}[3s])) - sum(rate(layer2_actual_requests_attempts_count{side=\"client\"}[3s]))", |
| 52 | + "legendFormat": "L2 retries" |
| 53 | + } |
| 54 | + ], |
| 55 | + "fieldConfig": {"defaults": {"unit": "reqps"}} |
| 56 | + }, |
| 57 | + { |
| 58 | + "title": "Route Success (L1 → L2 → L3)", |
| 59 | + "description": "Successful request routing path (2xx)", |
| 60 | + "type": "timeseries", |
| 61 | + "gridPos": {"h": 6, "w": 8, "x": 0, "y": 7}, |
| 62 | + "interval": "1s", |
| 63 | + "targets": [ |
| 64 | + {"expr": "sum by (layer2_node, layer3_node)(rate(layer1_route_total{http_status=\"200\"}[3s]))", "legendFormat": "{{layer2_node}} → {{layer3_node}}"} |
| 65 | + ], |
| 66 | + "fieldConfig": {"defaults": {"unit": "reqps"}} |
| 67 | + }, |
| 68 | + { |
| 69 | + "title": "Route Failure (L1 → L2 → L3)", |
| 70 | + "description": "Failed request routing path (non-2xx)", |
| 71 | + "type": "timeseries", |
| 72 | + "gridPos": {"h": 6, "w": 8, "x": 8, "y": 7}, |
| 73 | + "interval": "1s", |
| 74 | + "targets": [ |
| 75 | + {"expr": "sum by (layer2_node, layer3_node, http_status)(rate(layer1_route_total{http_status!=\"200\"}[3s]))", "legendFormat": "{{layer2_node}} → {{layer3_node}} {{http_status}}"} |
| 76 | + ], |
| 77 | + "fieldConfig": {"defaults": {"unit": "reqps"}} |
| 78 | + }, |
| 79 | + { |
| 80 | + "title": "Active Connections (by protocol)", |
| 81 | + "description": "Client connection pool — h2 = TLS, h2c = cleartext. Cycles every 5s due to max connection age.", |
| 82 | + "type": "timeseries", |
| 83 | + "gridPos": {"h": 6, "w": 8, "x": 16, "y": 7}, |
| 84 | + "interval": "1s", |
| 85 | + "targets": [ |
| 86 | + {"expr": "layer1_client_active_connections", "legendFormat": "L1 {{protocol}} → {{remote_ip}}"}, |
| 87 | + {"expr": "layer2_client_active_connections", "legendFormat": "L2 {{protocol}} → {{remote_ip}}"} |
| 88 | + ] |
| 89 | + }, |
| 90 | + { |
| 91 | + "title": "Route Distribution (L2)", |
| 92 | + "description": "Percentage of successful traffic routed to each L2 node", |
| 93 | + "type": "piechart", |
| 94 | + "gridPos": {"h": 6, "w": 8, "x": 0, "y": 13}, |
| 95 | + "interval": "1s", |
| 96 | + "targets": [{"expr": "sum by (layer2_node)(rate(layer1_route_total{http_status=\"200\"}[10s]))", "legendFormat": "{{layer2_node}}"}], |
| 97 | + "options": { |
| 98 | + "reduceOptions": {"calcs": ["lastNotNull"]}, |
| 99 | + "legend": {"displayMode": "table", "placement": "right", "values": ["percent"]}, |
| 100 | + "pieType": "donut" |
| 101 | + } |
| 102 | + }, |
| 103 | + { |
| 104 | + "title": "Route Distribution (L3)", |
| 105 | + "description": "Percentage of successful traffic routed to each L3 node", |
| 106 | + "type": "piechart", |
| 107 | + "gridPos": {"h": 6, "w": 8, "x": 8, "y": 13}, |
| 108 | + "interval": "1s", |
| 109 | + "targets": [{"expr": "sum by (layer3_node)(rate(layer1_route_total{http_status=\"200\"}[10s]))", "legendFormat": "{{layer3_node}}"}], |
| 110 | + "options": { |
| 111 | + "reduceOptions": {"calcs": ["lastNotNull"]}, |
| 112 | + "legend": {"displayMode": "table", "placement": "right", "values": ["percent"]}, |
| 113 | + "pieType": "donut" |
| 114 | + } |
| 115 | + }, |
| 116 | + { |
| 117 | + "title": "Route Distribution (L2 → L3)", |
| 118 | + "description": "Percentage of successful traffic per L2→L3 path", |
| 119 | + "type": "piechart", |
| 120 | + "gridPos": {"h": 6, "w": 8, "x": 16, "y": 13}, |
| 121 | + "interval": "1s", |
| 122 | + "targets": [ |
| 123 | + {"expr": "sum by (layer2_node, layer3_node)(rate(layer1_route_total{http_status=\"200\"}[10s]))", "legendFormat": "{{layer2_node}} → {{layer3_node}}"} |
| 124 | + ], |
| 125 | + "options": { |
| 126 | + "reduceOptions": {"calcs": ["lastNotNull"]}, |
| 127 | + "legend": {"displayMode": "table", "placement": "right", "values": ["percent"]}, |
| 128 | + "pieType": "donut" |
| 129 | + } |
| 130 | + }, |
| 131 | + {"title": "Control Plane", "type": "row", "gridPos": {"h": 1, "w": 24, "x": 0, "y": 20}, "collapsed": false}, |
| 132 | + { |
| 133 | + "title": "File Loaded", |
| 134 | + "type": "timeseries", |
| 135 | + "gridPos": {"h": 6, "w": 6, "x": 0, "y": 21}, |
| 136 | + "interval": "1s", |
| 137 | + "targets": [{"expr": "sum by (node) (rate(armeria_xds_configsource_file_loaded_total[3s]))", "legendFormat": "{{node}}"}], |
| 138 | + "fieldConfig": {"defaults": {"unit": "ops"}} |
| 139 | + }, |
| 140 | + { |
| 141 | + "title": "File Errors", |
| 142 | + "type": "timeseries", |
| 143 | + "gridPos": {"h": 6, "w": 6, "x": 6, "y": 21}, |
| 144 | + "interval": "1s", |
| 145 | + "targets": [{"expr": "sum by (node) (rate(armeria_xds_configsource_file_error_total[3s]))", "legendFormat": "{{node}}"}], |
| 146 | + "fieldConfig": {"defaults": {"unit": "ops"}} |
| 147 | + }, |
| 148 | + { |
| 149 | + "title": "Resources Active", |
| 150 | + "type": "timeseries", |
| 151 | + "gridPos": {"h": 6, "w": 6, "x": 12, "y": 21}, |
| 152 | + "interval": "1s", |
| 153 | + "targets": [{"expr": "armeria_xds_resource_node_revision", "legendFormat": "{{type}}/{{name}}"}] |
| 154 | + }, |
| 155 | + { |
| 156 | + "title": "Resource Errors", |
| 157 | + "type": "timeseries", |
| 158 | + "gridPos": {"h": 6, "w": 6, "x": 18, "y": 21}, |
| 159 | + "interval": "1s", |
| 160 | + "targets": [ |
| 161 | + {"expr": "rate(armeria_xds_resource_node_error_total[3s])", "legendFormat": "error {{type}}/{{name}}"}, |
| 162 | + {"expr": "rate(armeria_xds_resource_node_missing_total[3s])", "legendFormat": "missing {{type}}/{{name}}"} |
| 163 | + ], |
| 164 | + "fieldConfig": {"defaults": {"unit": "ops"}} |
| 165 | + }, |
| 166 | + {"title": "Load Balancer", "type": "row", "gridPos": {"h": 1, "w": 24, "x": 0, "y": 27}, "collapsed": false}, |
| 167 | + { |
| 168 | + "title": "Membership per Locality", |
| 169 | + "type": "timeseries", |
| 170 | + "gridPos": {"h": 6, "w": 8, "x": 0, "y": 28}, |
| 171 | + "interval": "1s", |
| 172 | + "targets": [{"expr": "armeria_xds_lb_membership{cluster=~\"$cluster\"}", "legendFormat": "{{cluster}} / {{region}}"}] |
| 173 | + }, |
| 174 | + { |
| 175 | + "title": "Healthy / Degraded Membership", |
| 176 | + "type": "timeseries", |
| 177 | + "gridPos": {"h": 6, "w": 8, "x": 8, "y": 28}, |
| 178 | + "interval": "1s", |
| 179 | + "targets": [ |
| 180 | + {"expr": "armeria_xds_lb_membership_healthy{cluster=~\"$cluster\"}", "legendFormat": "healthy {{cluster}}/{{region}}"}, |
| 181 | + {"expr": "armeria_xds_lb_membership_degraded{cluster=~\"$cluster\"}", "legendFormat": "degraded {{cluster}}/{{region}}"} |
| 182 | + ] |
| 183 | + }, |
| 184 | + { |
| 185 | + "title": "Locality Weights", |
| 186 | + "type": "timeseries", |
| 187 | + "gridPos": {"h": 6, "w": 8, "x": 16, "y": 28}, |
| 188 | + "interval": "1s", |
| 189 | + "targets": [{"expr": "armeria_xds_lb_locality_weight{cluster=~\"$cluster\"}", "legendFormat": "{{cluster}} / {{region}}"}] |
| 190 | + }, |
| 191 | + { |
| 192 | + "title": "Priority Load", |
| 193 | + "description": "Traffic distribution across priorities. In panic mode, all endpoints are treated as healthy regardless of actual health status.", |
| 194 | + "type": "timeseries", |
| 195 | + "gridPos": {"h": 6, "w": 12, "x": 0, "y": 34}, |
| 196 | + "interval": "1s", |
| 197 | + "targets": [ |
| 198 | + {"expr": "armeria_xds_lb_state_load_healthy{cluster=~\"$cluster\"}", "legendFormat": "healthy p{{priority}} {{cluster}}"}, |
| 199 | + {"expr": "armeria_xds_lb_state_load_degraded{cluster=~\"$cluster\"}", "legendFormat": "degraded p{{priority}} {{cluster}}"} |
| 200 | + ] |
| 201 | + }, |
| 202 | + { |
| 203 | + "title": "Panic Mode", |
| 204 | + "type": "timeseries", |
| 205 | + "gridPos": {"h": 6, "w": 6, "x": 12, "y": 34}, |
| 206 | + "interval": "1s", |
| 207 | + "targets": [{"expr": "armeria_xds_lb_state_panic{cluster=~\"$cluster\"}", "legendFormat": "{{cluster}} p{{priority}}"}] |
| 208 | + }, |
| 209 | + { |
| 210 | + "title": "Subsets", |
| 211 | + "type": "timeseries", |
| 212 | + "gridPos": {"h": 6, "w": 6, "x": 18, "y": 34}, |
| 213 | + "interval": "1s", |
| 214 | + "targets": [{"expr": "armeria_xds_lb_state_subsets{cluster=~\"$cluster\"}", "legendFormat": "{{cluster}}"}] |
| 215 | + }, |
| 216 | + {"title": "Zone-Aware Routing", "type": "row", "gridPos": {"h": 1, "w": 24, "x": 0, "y": 40}, "collapsed": false}, |
| 217 | + { |
| 218 | + "title": "ZAR Local Percentage", |
| 219 | + "description": "Percentage of traffic routed to the local zone (computed by Armeria ZAR algorithm)", |
| 220 | + "type": "bargauge", |
| 221 | + "gridPos": {"h": 6, "w": 12, "x": 0, "y": 41}, |
| 222 | + "interval": "1s", |
| 223 | + "targets": [ |
| 224 | + {"expr": "armeria_xds_lb_zar_local_percentage{cluster=~\"$cluster\",cluster!~\".*local.*\"}", "legendFormat": "{{node}} / {{cluster}}"} |
| 225 | + ], |
| 226 | + "options": { |
| 227 | + "orientation": "horizontal", |
| 228 | + "displayMode": "gradient", |
| 229 | + "reduceOptions": {"calcs": ["lastNotNull"]} |
| 230 | + }, |
| 231 | + "fieldConfig": {"defaults": {"unit": "percentunit", "min": 0, "max": 1}} |
| 232 | + }, |
| 233 | + { |
| 234 | + "title": "ZAR Residual Percentage per Locality", |
| 235 | + "description": "Residual traffic percentage for each locality after local zone allocation", |
| 236 | + "type": "table", |
| 237 | + "gridPos": {"h": 6, "w": 12, "x": 12, "y": 41}, |
| 238 | + "interval": "1s", |
| 239 | + "targets": [ |
| 240 | + { |
| 241 | + "expr": "armeria_xds_lb_zar_residual_percentage{cluster=~\"$cluster\",cluster!~\".*local.*\"}", |
| 242 | + "legendFormat": "{{node}} / {{cluster}} / {{region}}", |
| 243 | + "instant": true, |
| 244 | + "format": "table" |
| 245 | + } |
| 246 | + ], |
| 247 | + "transformations": [ |
| 248 | + { |
| 249 | + "id": "organize", |
| 250 | + "options": {"excludeByName": {"Time": true, "__name__": true, "instance": true, "job": true, "priority": true}, "renameByName": {"Value": "residual %"}} |
| 251 | + } |
| 252 | + ], |
| 253 | + "fieldConfig": {"defaults": {"unit": "percentunit"}, "overrides": []} |
| 254 | + }, |
| 255 | + {"title": "LB Selection", "type": "row", "gridPos": {"h": 1, "w": 24, "x": 0, "y": 47}, "collapsed": false}, |
| 256 | + { |
| 257 | + "title": "Selection Rate (hit vs miss)", |
| 258 | + "type": "timeseries", |
| 259 | + "gridPos": {"h": 6, "w": 12, "x": 0, "y": 48}, |
| 260 | + "interval": "1s", |
| 261 | + "targets": [ |
| 262 | + {"expr": "rate(armeria_xds_lb_select_total{result=\"hit\",cluster=~\"$cluster\"}[3s])", "legendFormat": "hit {{cluster}}/{{region}}"}, |
| 263 | + {"expr": "rate(armeria_xds_lb_select_total{result=\"miss\",cluster=~\"$cluster\"}[3s])", "legendFormat": "miss {{cluster}}/{{region}}"} |
| 264 | + ], |
| 265 | + "fieldConfig": {"defaults": {"unit": "ops"}} |
| 266 | + }, |
| 267 | + { |
| 268 | + "title": "Errors (no_endpoints / no_host_source)", |
| 269 | + "type": "timeseries", |
| 270 | + "gridPos": {"h": 6, "w": 12, "x": 12, "y": 48}, |
| 271 | + "interval": "1s", |
| 272 | + "targets": [ |
| 273 | + {"expr": "rate(armeria_xds_lb_select_total{result=\"no_endpoints\",cluster=~\"$cluster\"}[3s])", "legendFormat": "no_endpoints {{cluster}}"}, |
| 274 | + {"expr": "rate(armeria_xds_lb_select_total{result=\"no_host_source\",cluster=~\"$cluster\"}[3s])", "legendFormat": "no_host_source {{cluster}}"} |
| 275 | + ], |
| 276 | + "fieldConfig": {"defaults": {"unit": "ops"}} |
| 277 | + }, |
| 278 | + {"title": "LB Update Events", "type": "row", "gridPos": {"h": 1, "w": 24, "x": 0, "y": 54}, "collapsed": false}, |
| 279 | + { |
| 280 | + "title": "Resource / Endpoint / State Updates", |
| 281 | + "type": "timeseries", |
| 282 | + "gridPos": {"h": 6, "w": 12, "x": 0, "y": 55}, |
| 283 | + "interval": "1s", |
| 284 | + "targets": [ |
| 285 | + {"expr": "rate(armeria_xds_lb_resource_updated_count_total{cluster=~\"$cluster\"}[3s])", "legendFormat": "resource {{cluster}}"}, |
| 286 | + {"expr": "rate(armeria_xds_lb_endpoints_updated_count_total{cluster=~\"$cluster\"}[3s])", "legendFormat": "endpoints {{cluster}}"}, |
| 287 | + {"expr": "rate(armeria_xds_lb_state_updated_count_total{cluster=~\"$cluster\"}[3s])", "legendFormat": "state {{cluster}}"}, |
| 288 | + {"expr": "rate(armeria_xds_lb_state_rejected_count_total{cluster=~\"$cluster\"}[3s])", "legendFormat": "rejected {{cluster}}"} |
| 289 | + ], |
| 290 | + "fieldConfig": {"defaults": {"unit": "ops"}} |
| 291 | + }, |
| 292 | + { |
| 293 | + "title": "Update Revisions", |
| 294 | + "type": "timeseries", |
| 295 | + "gridPos": {"h": 6, "w": 12, "x": 12, "y": 55}, |
| 296 | + "interval": "1s", |
| 297 | + "targets": [ |
| 298 | + {"expr": "armeria_xds_lb_resource_updated_revision{cluster=~\"$cluster\"}", "legendFormat": "resource {{cluster}}"}, |
| 299 | + {"expr": "armeria_xds_lb_state_updated_revision{cluster=~\"$cluster\"}", "legendFormat": "state {{cluster}}"} |
| 300 | + ] |
| 301 | + } |
| 302 | + ] |
| 303 | +} |
0 commit comments