| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package k8s_apiserver |
| 4 | |
| 5 | import "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi" |
| 6 | |
| 7 | type ( |
| 8 | Charts = collectorapi.Charts |
| 9 | Chart = collectorapi.Chart |
| 10 | Dims = collectorapi.Dims |
| 11 | Dim = collectorapi.Dim |
| 12 | ) |
| 13 | |
| 14 | var baseCharts = Charts{ |
| 15 | // === Overview === |
| 16 | requestsTotalChart.Copy(), |
| 17 | requestsDroppedChart.Copy(), |
| 18 | |
| 19 | // === Requests === |
| 20 | requestsByVerbChart.Copy(), |
| 21 | requestsByCodeChart.Copy(), |
| 22 | requestsByResourceChart.Copy(), |
| 23 | |
| 24 | // === Latency === |
| 25 | requestLatencyChart.Copy(), |
| 26 | responseSizeChart.Copy(), |
| 27 | |
| 28 | // === Inflight === |
| 29 | inflightRequestsChart.Copy(), |
| 30 | longrunningRequestsChart.Copy(), |
| 31 | |
| 32 | // === REST Client === |
| 33 | restClientRequestsByCodeChart.Copy(), |
| 34 | restClientRequestsByMethodChart.Copy(), |
| 35 | restClientLatencyChart.Copy(), |
| 36 | |
| 37 | // === Admission === |
| 38 | admissionStepLatencyChart.Copy(), |
| 39 | |
| 40 | // === Audit === |
| 41 | auditEventsChart.Copy(), |
| 42 | |
| 43 | // === Authentication === |
| 44 | authRequestsChart.Copy(), |
| 45 | |
| 46 | // === Process === |
| 47 | goroutinesChart.Copy(), |
| 48 | threadsChart.Copy(), |
| 49 | processMemoryChart.Copy(), |
| 50 | heapMemoryChart.Copy(), |
| 51 | gcDurationChart.Copy(), |
| 52 | openFDsChart.Copy(), |
| 53 | cpuUsageChart.Copy(), |
| 54 | } |
| 55 | |
| 56 | // === Overview Family === |
| 57 | |
| 58 | var requestsTotalChart = Chart{ |
| 59 | ID: "requests_total", |
| 60 | Title: "API Server Request Rate", |
| 61 | Units: "requests/s", |
| 62 | Fam: "requests", |
| 63 | Ctx: "k8s_apiserver.requests_total", |
| 64 | Type: collectorapi.Line, |
| 65 | Dims: Dims{ |
| 66 | {ID: "request_total", Name: "requests", Algo: collectorapi.Incremental}, |
| 67 | }, |
| 68 | } |
| 69 | |
| 70 | var requestsDroppedChart = Chart{ |
| 71 | ID: "requests_dropped", |
| 72 | Title: "API Server Dropped Requests", |
| 73 | Units: "requests/s", |
| 74 | Fam: "requests", |
| 75 | Ctx: "k8s_apiserver.requests_dropped", |
| 76 | Type: collectorapi.Line, |
| 77 | Dims: Dims{ |
| 78 | {ID: "request_dropped_total", Name: "dropped", Algo: collectorapi.Incremental}, |
| 79 | }, |
| 80 | } |
| 81 | |
| 82 | // === Requests Family === |
| 83 | |
| 84 | var requestsByVerbChart = Chart{ |
| 85 | ID: "requests_by_verb", |
| 86 | Title: "API Server Requests By Verb", |
| 87 | Units: "requests/s", |
| 88 | Fam: "requests", |
| 89 | Ctx: "k8s_apiserver.requests_by_verb", |
| 90 | Type: collectorapi.Stacked, |
| 91 | // Dims added dynamically |
| 92 | } |
| 93 | |
| 94 | var requestsByCodeChart = Chart{ |
| 95 | ID: "requests_by_code", |
| 96 | Title: "API Server Requests By Status Code", |
| 97 | Units: "requests/s", |
| 98 | Fam: "requests", |
| 99 | Ctx: "k8s_apiserver.requests_by_code", |
| 100 | Type: collectorapi.Stacked, |
| 101 | // Dims added dynamically |
| 102 | } |
| 103 | |
| 104 | var requestsByResourceChart = Chart{ |
| 105 | ID: "requests_by_resource", |
| 106 | Title: "API Server Requests By Resource", |
| 107 | Units: "requests/s", |
| 108 | Fam: "requests", |
| 109 | Ctx: "k8s_apiserver.requests_by_resource", |
| 110 | Type: collectorapi.Stacked, |
| 111 | // Dims added dynamically |
| 112 | } |
| 113 | |
| 114 | // === Latency Family === |
| 115 | |
| 116 | var requestLatencyChart = Chart{ |
| 117 | ID: "request_latency", |
| 118 | Title: "API Server Request Latency", |
| 119 | Units: "milliseconds", |
| 120 | Fam: "latency", |
| 121 | Ctx: "k8s_apiserver.request_latency", |
| 122 | Type: collectorapi.Line, |
| 123 | Dims: Dims{ |
| 124 | {ID: "request_latency_p50", Name: "p50", Div: 1000}, |
| 125 | {ID: "request_latency_p90", Name: "p90", Div: 1000}, |
| 126 | {ID: "request_latency_p99", Name: "p99", Div: 1000}, |
| 127 | }, |
| 128 | } |
| 129 | |
| 130 | var responseSizeChart = Chart{ |
| 131 | ID: "response_size", |
| 132 | Title: "API Server Response Size", |
| 133 | Units: "bytes", |
| 134 | Fam: "latency", |
| 135 | Ctx: "k8s_apiserver.response_size", |
| 136 | Type: collectorapi.Line, |
| 137 | Dims: Dims{ |
| 138 | {ID: "request_response_size_p50", Name: "p50"}, |
| 139 | {ID: "request_response_size_p90", Name: "p90"}, |
| 140 | {ID: "request_response_size_p99", Name: "p99"}, |
| 141 | }, |
| 142 | } |
| 143 | |
| 144 | // === Inflight Family === |
| 145 | |
| 146 | var inflightRequestsChart = Chart{ |
| 147 | ID: "inflight_requests", |
| 148 | Title: "API Server Inflight Requests", |
| 149 | Units: "requests", |
| 150 | Fam: "inflight", |
| 151 | Ctx: "k8s_apiserver.inflight_requests", |
| 152 | Type: collectorapi.Stacked, |
| 153 | Dims: Dims{ |
| 154 | {ID: "inflight_mutating", Name: "mutating"}, |
| 155 | {ID: "inflight_readonly", Name: "read_only"}, |
| 156 | }, |
| 157 | } |
| 158 | |
| 159 | var longrunningRequestsChart = Chart{ |
| 160 | ID: "longrunning_requests", |
| 161 | Title: "API Server Long-Running Requests", |
| 162 | Units: "requests", |
| 163 | Fam: "inflight", |
| 164 | Ctx: "k8s_apiserver.longrunning_requests", |
| 165 | Type: collectorapi.Line, |
| 166 | Dims: Dims{ |
| 167 | {ID: "inflight_longrunning", Name: "longrunning"}, |
| 168 | }, |
| 169 | } |
| 170 | |
| 171 | // === REST Client Family === |
| 172 | |
| 173 | var restClientRequestsByCodeChart = Chart{ |
| 174 | ID: "rest_client_requests_by_code", |
| 175 | Title: "REST Client Requests By Status Code", |
| 176 | Units: "requests/s", |
| 177 | Fam: "rest client", |
| 178 | Ctx: "k8s_apiserver.rest_client_requests_by_code", |
| 179 | Type: collectorapi.Stacked, |
| 180 | // Dims added dynamically |
| 181 | } |
| 182 | |
| 183 | var restClientRequestsByMethodChart = Chart{ |
| 184 | ID: "rest_client_requests_by_method", |
| 185 | Title: "REST Client Requests By Method", |
| 186 | Units: "requests/s", |
| 187 | Fam: "rest client", |
| 188 | Ctx: "k8s_apiserver.rest_client_requests_by_method", |
| 189 | Type: collectorapi.Stacked, |
| 190 | // Dims added dynamically |
| 191 | } |
| 192 | |
| 193 | var restClientLatencyChart = Chart{ |
| 194 | ID: "rest_client_latency", |
| 195 | Title: "REST Client Request Latency", |
| 196 | Units: "milliseconds", |
| 197 | Fam: "rest client", |
| 198 | Ctx: "k8s_apiserver.rest_client_latency", |
| 199 | Type: collectorapi.Line, |
| 200 | Dims: Dims{ |
| 201 | {ID: "rest_client_latency_p50", Name: "p50", Div: 1000}, |
| 202 | {ID: "rest_client_latency_p90", Name: "p90", Div: 1000}, |
| 203 | {ID: "rest_client_latency_p99", Name: "p99", Div: 1000}, |
| 204 | }, |
| 205 | } |
| 206 | |
| 207 | // === Admission Family === |
| 208 | |
| 209 | var admissionStepLatencyChart = Chart{ |
| 210 | ID: "admission_step_latency", |
| 211 | Title: "Admission Step Latency", |
| 212 | Units: "milliseconds", |
| 213 | Fam: "admission", |
| 214 | Ctx: "k8s_apiserver.admission_step_latency", |
| 215 | Type: collectorapi.Line, |
| 216 | Dims: Dims{ |
| 217 | {ID: "admission_step_latency_validate", Name: "validate", Div: 1000}, |
| 218 | {ID: "admission_step_latency_admit", Name: "admit", Div: 1000}, |
| 219 | }, |
| 220 | } |
| 221 | |
| 222 | // Dynamic charts for admission controllers and webhooks are created in collect.go |
| 223 | |
| 224 | // === Etcd Family === |
| 225 | |
| 226 | // Dynamic chart for etcd object counts is created in collect.go |
| 227 | |
| 228 | // === Audit Family === |
| 229 | |
| 230 | var auditEventsChart = Chart{ |
| 231 | ID: "audit_events", |
| 232 | Title: "API Server Audit Events", |
| 233 | Units: "events/s", |
| 234 | Fam: "audit", |
| 235 | Ctx: "k8s_apiserver.audit_events", |
| 236 | Type: collectorapi.Line, |
| 237 | Dims: Dims{ |
| 238 | {ID: "audit_events_total", Name: "events", Algo: collectorapi.Incremental}, |
| 239 | {ID: "audit_rejected_total", Name: "rejected", Algo: collectorapi.Incremental}, |
| 240 | }, |
| 241 | } |
| 242 | |
| 243 | // === Authentication Family === |
| 244 | |
| 245 | var authRequestsChart = Chart{ |
| 246 | ID: "authentication_requests", |
| 247 | Title: "API Server Authenticated Requests", |
| 248 | Units: "requests/s", |
| 249 | Fam: "authentication", |
| 250 | Ctx: "k8s_apiserver.authentication_requests", |
| 251 | Type: collectorapi.Line, |
| 252 | Dims: Dims{ |
| 253 | {ID: "auth_authenticated_requests_total", Name: "authenticated", Algo: collectorapi.Incremental}, |
| 254 | }, |
| 255 | } |
| 256 | |
| 257 | // === Process Family === |
| 258 | |
| 259 | var goroutinesChart = Chart{ |
| 260 | ID: "goroutines", |
| 261 | Title: "Goroutines", |
| 262 | Units: "goroutines", |
| 263 | Fam: "process", |
| 264 | Ctx: "k8s_apiserver.goroutines", |
| 265 | Type: collectorapi.Line, |
| 266 | Dims: Dims{ |
| 267 | {ID: "process_goroutines", Name: "goroutines"}, |
| 268 | }, |
| 269 | } |
| 270 | |
| 271 | var threadsChart = Chart{ |
| 272 | ID: "threads", |
| 273 | Title: "OS Threads", |
| 274 | Units: "threads", |
| 275 | Fam: "process", |
| 276 | Ctx: "k8s_apiserver.threads", |
| 277 | Type: collectorapi.Line, |
| 278 | Dims: Dims{ |
| 279 | {ID: "process_threads", Name: "threads"}, |
| 280 | }, |
| 281 | } |
| 282 | |
| 283 | var processMemoryChart = Chart{ |
| 284 | ID: "process_memory", |
| 285 | Title: "Process Memory", |
| 286 | Units: "bytes", |
| 287 | Fam: "process", |
| 288 | Ctx: "k8s_apiserver.process_memory", |
| 289 | Type: collectorapi.Stacked, |
| 290 | Dims: Dims{ |
| 291 | {ID: "process_resident_memory_bytes", Name: "resident"}, |
| 292 | {ID: "process_virtual_memory_bytes", Name: "virtual"}, |
| 293 | }, |
| 294 | } |
| 295 | |
| 296 | var heapMemoryChart = Chart{ |
| 297 | ID: "heap_memory", |
| 298 | Title: "Go Heap Memory", |
| 299 | Units: "bytes", |
| 300 | Fam: "process", |
| 301 | Ctx: "k8s_apiserver.heap_memory", |
| 302 | Type: collectorapi.Stacked, |
| 303 | Dims: Dims{ |
| 304 | {ID: "process_heap_alloc_bytes", Name: "alloc"}, |
| 305 | {ID: "process_heap_inuse_bytes", Name: "inuse"}, |
| 306 | {ID: "process_stack_inuse_bytes", Name: "stack"}, |
| 307 | }, |
| 308 | } |
| 309 | |
| 310 | var gcDurationChart = Chart{ |
| 311 | ID: "gc_duration", |
| 312 | Title: "GC Duration", |
| 313 | Units: "seconds", |
| 314 | Fam: "process", |
| 315 | Ctx: "k8s_apiserver.gc_duration", |
| 316 | Type: collectorapi.Line, |
| 317 | Dims: Dims{ |
| 318 | {ID: "process_gc_duration_min", Name: "min", Div: 1000000}, |
| 319 | {ID: "process_gc_duration_p25", Name: "p25", Div: 1000000}, |
| 320 | {ID: "process_gc_duration_p50", Name: "p50", Div: 1000000}, |
| 321 | {ID: "process_gc_duration_p75", Name: "p75", Div: 1000000}, |
| 322 | {ID: "process_gc_duration_max", Name: "max", Div: 1000000}, |
| 323 | }, |
| 324 | } |
| 325 | |
| 326 | var openFDsChart = Chart{ |
| 327 | ID: "open_fds", |
| 328 | Title: "Open File Descriptors", |
| 329 | Units: "file descriptors", |
| 330 | Fam: "process", |
| 331 | Ctx: "k8s_apiserver.open_fds", |
| 332 | Type: collectorapi.Line, |
| 333 | Dims: Dims{ |
| 334 | {ID: "process_open_fds", Name: "open"}, |
| 335 | {ID: "process_max_fds", Name: "max"}, |
| 336 | }, |
| 337 | } |
| 338 | |
| 339 | var cpuUsageChart = Chart{ |
| 340 | ID: "cpu_usage", |
| 341 | Title: "CPU Usage", |
| 342 | Units: "seconds/s", |
| 343 | Fam: "process", |
| 344 | Ctx: "k8s_apiserver.cpu_usage", |
| 345 | Type: collectorapi.Line, |
| 346 | Dims: Dims{ |
| 347 | {ID: "process_cpu_seconds_total", Name: "cpu", Algo: collectorapi.Incremental, Div: 1000}, |
| 348 | }, |
| 349 | } |
| 350 | |
| 351 | // === Dynamic Chart Templates === |
| 352 | |
| 353 | func newWorkqueueDepthChart(name string) *Chart { |
| 354 | return &Chart{ |
| 355 | ID: "workqueue_depth_" + name, |
| 356 | Title: "Work Queue Depth", |
| 357 | Units: "items", |
| 358 | Fam: "workqueue", |
| 359 | Ctx: "k8s_apiserver.workqueue_depth", |
| 360 | Type: collectorapi.Line, |
| 361 | Dims: Dims{ |
| 362 | {ID: "workqueue_" + name + "_depth", Name: "depth"}, |
| 363 | }, |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | func newWorkqueueLatencyChart(name string) *Chart { |
| 368 | return &Chart{ |
| 369 | ID: "workqueue_latency_" + name, |
| 370 | Title: "Work Queue Latency", |
| 371 | Units: "microseconds", |
| 372 | Fam: "workqueue", |
| 373 | Ctx: "k8s_apiserver.workqueue_latency", |
| 374 | Type: collectorapi.Line, |
| 375 | Dims: Dims{ |
| 376 | {ID: "workqueue_" + name + "_latency_p50", Name: "p50"}, |
| 377 | {ID: "workqueue_" + name + "_latency_p90", Name: "p90"}, |
| 378 | {ID: "workqueue_" + name + "_latency_p99", Name: "p99"}, |
| 379 | }, |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | func newWorkqueueAddsChart(name string) *Chart { |
| 384 | return &Chart{ |
| 385 | ID: "workqueue_adds_" + name, |
| 386 | Title: "Work Queue Adds", |
| 387 | Units: "items/s", |
| 388 | Fam: "workqueue", |
| 389 | Ctx: "k8s_apiserver.workqueue_adds", |
| 390 | Type: collectorapi.Line, |
| 391 | Dims: Dims{ |
| 392 | {ID: "workqueue_" + name + "_adds_total", Name: "adds", Algo: collectorapi.Incremental}, |
| 393 | {ID: "workqueue_" + name + "_retries_total", Name: "retries", Algo: collectorapi.Incremental}, |
| 394 | }, |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | func newWorkqueueDurationChart(name string) *Chart { |
| 399 | return &Chart{ |
| 400 | ID: "workqueue_duration_" + name, |
| 401 | Title: "Work Queue Work Duration", |
| 402 | Units: "microseconds", |
| 403 | Fam: "workqueue", |
| 404 | Ctx: "k8s_apiserver.workqueue_duration", |
| 405 | Type: collectorapi.Line, |
| 406 | Dims: Dims{ |
| 407 | {ID: "workqueue_" + name + "_duration_p50", Name: "p50"}, |
| 408 | {ID: "workqueue_" + name + "_duration_p90", Name: "p90"}, |
| 409 | {ID: "workqueue_" + name + "_duration_p99", Name: "p99"}, |
| 410 | }, |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | func newAdmissionControllerLatencyChart(name string) *Chart { |
| 415 | // Heatmap chart with histogram bucket dimensions |
| 416 | // K8s admission controller histogram buckets: 5ms, 25ms, 100ms, 500ms, 1s, 2.5s, +Inf |
| 417 | return &Chart{ |
| 418 | ID: "admission_controller_latency_" + name, |
| 419 | Title: "Admission Controller Latency", |
| 420 | Units: "events/s", |
| 421 | Fam: "admission", |
| 422 | Ctx: "k8s_apiserver.admission_controller_latency", |
| 423 | Type: collectorapi.Heatmap, |
| 424 | Dims: Dims{ |
| 425 | {ID: "admission_controller_" + name + "_bucket_5ms", Name: "5ms", Algo: collectorapi.Incremental}, |
| 426 | {ID: "admission_controller_" + name + "_bucket_25ms", Name: "25ms", Algo: collectorapi.Incremental}, |
| 427 | {ID: "admission_controller_" + name + "_bucket_100ms", Name: "100ms", Algo: collectorapi.Incremental}, |
| 428 | {ID: "admission_controller_" + name + "_bucket_500ms", Name: "500ms", Algo: collectorapi.Incremental}, |
| 429 | {ID: "admission_controller_" + name + "_bucket_1s", Name: "1s", Algo: collectorapi.Incremental}, |
| 430 | {ID: "admission_controller_" + name + "_bucket_2500ms", Name: "2.5s", Algo: collectorapi.Incremental}, |
| 431 | {ID: "admission_controller_" + name + "_bucket_inf", Name: "+Inf", Algo: collectorapi.Incremental}, |
| 432 | }, |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | func newAdmissionWebhookLatencyChart(name string) *Chart { |
| 437 | // Heatmap chart with histogram bucket dimensions |
| 438 | // K8s admission webhook histogram buckets: 5ms, 25ms, 100ms, 500ms, 1s, 2.5s, +Inf |
| 439 | return &Chart{ |
| 440 | ID: "admission_webhook_latency_" + name, |
| 441 | Title: "Admission Webhook Latency", |
| 442 | Units: "events/s", |
| 443 | Fam: "admission", |
| 444 | Ctx: "k8s_apiserver.admission_webhook_latency", |
| 445 | Type: collectorapi.Heatmap, |
| 446 | Dims: Dims{ |
| 447 | {ID: "admission_webhook_" + name + "_bucket_5ms", Name: "5ms", Algo: collectorapi.Incremental}, |
| 448 | {ID: "admission_webhook_" + name + "_bucket_25ms", Name: "25ms", Algo: collectorapi.Incremental}, |
| 449 | {ID: "admission_webhook_" + name + "_bucket_100ms", Name: "100ms", Algo: collectorapi.Incremental}, |
| 450 | {ID: "admission_webhook_" + name + "_bucket_500ms", Name: "500ms", Algo: collectorapi.Incremental}, |
| 451 | {ID: "admission_webhook_" + name + "_bucket_1s", Name: "1s", Algo: collectorapi.Incremental}, |
| 452 | {ID: "admission_webhook_" + name + "_bucket_2500ms", Name: "2.5s", Algo: collectorapi.Incremental}, |
| 453 | {ID: "admission_webhook_" + name + "_bucket_inf", Name: "+Inf", Algo: collectorapi.Incremental}, |
| 454 | }, |
| 455 | } |
| 456 | } |
| 457 | |
| 458 | func newEtcdObjectCountsChart() *Chart { |
| 459 | return &Chart{ |
| 460 | ID: "etcd_object_counts", |
| 461 | Title: "Objects Stored In Etcd", |
| 462 | Units: "objects", |
| 463 | Fam: "etcd", |
| 464 | Ctx: "k8s_apiserver.etcd_object_counts", |
| 465 | Type: collectorapi.Stacked, |
| 466 | // Dims added dynamically per resource type |
| 467 | } |
| 468 | } |