1
16
17 package collectors
18
19 import (
20 "context"
21 "fmt"
22 "time"
23
24 "k8s.io/component-base/metrics"
25 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
26 "k8s.io/klog/v2"
27 )
28
29 type criMetricsCollector struct {
30 metrics.BaseStableCollector
31
32
33 descriptors map[string]*metrics.Desc
34 listPodSandboxMetricsFn func(context.Context) ([]*runtimeapi.PodSandboxMetrics, error)
35 }
36
37
38 var _ metrics.StableCollector = &criMetricsCollector{}
39
40
41 func NewCRIMetricsCollector(ctx context.Context, listPodSandboxMetricsFn func(context.Context) ([]*runtimeapi.PodSandboxMetrics, error), listMetricDescriptorsFn func(context.Context) ([]*runtimeapi.MetricDescriptor, error)) metrics.StableCollector {
42 descs, err := listMetricDescriptorsFn(ctx)
43 if err != nil {
44 klog.ErrorS(err, "Error reading MetricDescriptors")
45 return &criMetricsCollector{
46 listPodSandboxMetricsFn: listPodSandboxMetricsFn,
47 }
48 }
49 c := &criMetricsCollector{
50 listPodSandboxMetricsFn: listPodSandboxMetricsFn,
51 descriptors: make(map[string]*metrics.Desc, len(descs)),
52 }
53
54 for _, desc := range descs {
55 c.descriptors[desc.Name] = criDescToProm(desc)
56 }
57
58 return c
59 }
60
61
62 func (c *criMetricsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
63 for _, desc := range c.descriptors {
64 ch <- desc
65 }
66 }
67
68
69
70 func (c *criMetricsCollector) CollectWithStability(ch chan<- metrics.Metric) {
71 podMetrics, err := c.listPodSandboxMetricsFn(context.Background())
72 if err != nil {
73 klog.ErrorS(err, "Failed to get pod metrics")
74 return
75 }
76
77 for _, podMetric := range podMetrics {
78 for _, metric := range podMetric.GetMetrics() {
79 promMetric, err := c.criMetricToProm(metric)
80 if err == nil {
81 ch <- promMetric
82 }
83 }
84 for _, ctrMetric := range podMetric.GetContainerMetrics() {
85 for _, metric := range ctrMetric.GetMetrics() {
86 promMetric, err := c.criMetricToProm(metric)
87 if err == nil {
88 ch <- promMetric
89 }
90 }
91 }
92 }
93 }
94
95 func criDescToProm(m *runtimeapi.MetricDescriptor) *metrics.Desc {
96
97
98 return metrics.NewDesc(m.Name, m.Help, m.LabelKeys, nil, metrics.INTERNAL, "")
99 }
100
101 func (c *criMetricsCollector) criMetricToProm(m *runtimeapi.Metric) (metrics.Metric, error) {
102 desc, ok := c.descriptors[m.Name]
103 if !ok {
104 err := fmt.Errorf("error converting CRI Metric to prometheus format")
105 klog.V(5).ErrorS(err, "Descriptor not present in pre-populated list of descriptors", "name", m.Name)
106 return nil, err
107 }
108
109 typ := criTypeToProm[m.MetricType]
110
111 pm, err := metrics.NewConstMetric(desc, typ, float64(m.GetValue().Value), m.LabelValues...)
112 if err != nil {
113 klog.ErrorS(err, "Error getting CRI prometheus metric", "descriptor", desc.String())
114 return nil, err
115 }
116
117
118
119
120 if m.Timestamp == 0 {
121 return pm, nil
122 }
123 return metrics.NewLazyMetricWithTimestamp(time.Unix(0, m.Timestamp), pm), nil
124 }
125
126 var criTypeToProm = map[runtimeapi.MetricType]metrics.ValueType{
127 runtimeapi.MetricType_COUNTER: metrics.CounterValue,
128 runtimeapi.MetricType_GAUGE: metrics.GaugeValue,
129 }
130
View as plain text