diff --git a/docs/pod-metrics.md b/docs/pod-metrics.md index 627ae4f90c..74c0bf2d94 100644 --- a/docs/pod-metrics.md +++ b/docs/pod-metrics.md @@ -11,6 +11,7 @@ | kube_pod_labels | Gauge | Kubernetes labels converted to Prometheus labels | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`label_POD_LABEL`=<POD_LABEL>
`uid`=<pod-uid> | STABLE | - | | kube_pod_nodeselectors| Gauge | Describes the Pod nodeSelectors | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`nodeselector_NODE_SELECTOR`=<NODE_SELECTOR>
`uid`=<pod-uid> | EXPERIMENTAL | Opt-in | | kube_pod_status_phase | Gauge | The pods current phase | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`phase`=<Pending\|Running\|Succeeded\|Failed\|Unknown>
`uid`=<pod-uid> | STABLE | - | +| kube_pod_status_qos_class | Gauge | The pods current qosClass | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`qos_class`=<BestEffort\|Burstable\|Guaranteed>
`uid`=<pod-uid> | EXPERIMENTAL | - | | kube_pod_status_ready | Gauge | Describes whether the pod is ready to serve requests | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`condition`=<true\|false\|unknown>
`uid`=<pod-uid> | STABLE | - | | kube_pod_status_scheduled | Gauge | Describes the status of the scheduling process for the pod | |`pod`=<pod-name>
`namespace`=<pod-namespace>
`condition`=<true\|false\|unknown>
`uid`=<pod-uid> | STABLE | - | | kube_pod_container_info | Gauge | Information about a container in a pod | | `container`=<container-name>
`pod`=<pod-name>
`namespace`=<pod-namespace>
`image`=<image-name>
`image_id`=<image-id>
`image_spec`=<image-spec>
`container_id`=<containerid>
`uid`=<pod-uid> | STABLE | - | diff --git a/internal/store/pod.go b/internal/store/pod.go index f9bfdd21f2..9d7fbc4f3d 100644 --- a/internal/store/pod.go +++ b/internal/store/pod.go @@ -82,6 +82,7 @@ func podMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generat createPodSpecVolumesPersistentVolumeClaimsReadonlyFamilyGenerator(), createPodStartTimeFamilyGenerator(), createPodStatusPhaseFamilyGenerator(), + createPodStatusQosClassFamilyGenerator(), createPodStatusReadyFamilyGenerator(), createPodStatusReasonFamilyGenerator(), createPodStatusScheduledFamilyGenerator(), @@ -1317,6 +1318,48 @@ func createPodStatusPhaseFamilyGenerator() generator.FamilyGenerator { ) } +func createPodStatusQosClassFamilyGenerator() generator.FamilyGenerator { + return *generator.NewFamilyGeneratorWithStability( + "kube_pod_status_qos_class", + "The pods current qosClass.", + metric.Gauge, + basemetrics.ALPHA, + "", + wrapPodFunc(func(p *v1.Pod) *metric.Family { + class := p.Status.QOSClass + if class == "" { + return &metric.Family{ + Metrics: []*metric.Metric{}, + } + } + + qosClasses := []struct { + v bool + n string + }{ + {class == v1.PodQOSBestEffort, string(v1.PodQOSBestEffort)}, + {class == v1.PodQOSBurstable, string(v1.PodQOSBurstable)}, + {class == v1.PodQOSGuaranteed, string(v1.PodQOSGuaranteed)}, + } + + ms := make([]*metric.Metric, len(qosClasses)) + + for i, p := range qosClasses { + ms[i] = &metric.Metric{ + + LabelKeys: []string{"qos_class"}, + LabelValues: []string{p.n}, + Value: boolFloat64(p.v), + } + } + + return &metric.Family{ + Metrics: ms, + } + }), + ) +} + func createPodStatusReadyFamilyGenerator() generator.FamilyGenerator { return *generator.NewFamilyGeneratorWithStability( "kube_pod_status_ready", diff --git a/internal/store/pod_test.go b/internal/store/pod_test.go index fb118f2d1c..1f42d0b7c4 100644 --- a/internal/store/pod_test.go +++ b/internal/store/pod_test.go @@ -1294,6 +1294,26 @@ func TestPodStore(t *testing.T) { `, MetricNames: []string{"kube_pod_status_phase", "kube_pod_status_reason"}, }, + { + Obj: &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + Namespace: "ns1", + UID: "uid1", + }, + Status: v1.PodStatus{ + QOSClass: v1.PodQOSBestEffort, + }, + }, + Want: ` + # HELP kube_pod_status_qos_class The pods current qosClass. + # TYPE kube_pod_status_qos_class gauge + kube_pod_status_qos_class{namespace="ns1",qos_class="BestEffort",pod="pod1",uid="uid1"} 1 + kube_pod_status_qos_class{namespace="ns1",qos_class="Burstable",pod="pod1",uid="uid1"} 0 + kube_pod_status_qos_class{namespace="ns1",qos_class="Guaranteed",pod="pod1",uid="uid1"} 0 +`, + MetricNames: []string{"kube_pod_status_qos_class"}, + }, { Obj: &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -2079,7 +2099,7 @@ func BenchmarkPodStore(b *testing.B) { }, } - expectedFamilies := 47 + expectedFamilies := 48 for n := 0; n < b.N; n++ { families := f(pod) if len(families) != expectedFamilies { diff --git a/pkg/app/server_test.go b/pkg/app/server_test.go index 659b84bf24..aefeef891a 100644 --- a/pkg/app/server_test.go +++ b/pkg/app/server_test.go @@ -238,6 +238,7 @@ func TestFullScrapeCycle(t *testing.T) { # HELP kube_pod_spec_volumes_persistentvolumeclaims_info [STABLE] Information about persistentvolumeclaim volumes in a pod. # HELP kube_pod_spec_volumes_persistentvolumeclaims_readonly [STABLE] Describes whether a persistentvolumeclaim is mounted read only. # HELP kube_pod_start_time [STABLE] Start time in unix timestamp for a pod. +# HELP kube_pod_status_qos_class The pods current qosClass. # HELP kube_pod_status_phase [STABLE] The pods current phase. # HELP kube_pod_status_ready [STABLE] Describes whether the pod is ready to serve requests. # HELP kube_pod_status_reason The pod status reasons @@ -285,6 +286,7 @@ func TestFullScrapeCycle(t *testing.T) { # TYPE kube_pod_spec_volumes_persistentvolumeclaims_readonly gauge # TYPE kube_pod_start_time gauge # TYPE kube_pod_status_phase gauge +# TYPE kube_pod_status_qos_class gauge # TYPE kube_pod_status_ready gauge # TYPE kube_pod_status_reason gauge # TYPE kube_pod_status_scheduled gauge