@@ -20,6 +20,7 @@ import (
20
20
"time"
21
21
22
22
v1 "github.com/containerd/containerd/metrics/types/v1"
23
+ v2 "github.com/containerd/containerd/metrics/types/v2"
23
24
"k8s.io/apimachinery/pkg/util/sets"
24
25
"sigs.k8s.io/usage-metrics-collector/pkg/ctrstats"
25
26
)
@@ -45,23 +46,42 @@ func (s *sampleCache) getContainerCPUAndMemoryCM() (cpuMetrics, memoryMetrics, e
45
46
log .V (9 ).Info ("found containers" , "count" , len (containers ))
46
47
47
48
for _ , c := range containers {
48
- // TODO: is this a reasonable key for the metric read time?
49
49
readTime := s .metricsReader .readTimeFunc (c .PodID + "/" + c .ContainerID )
50
- stats , err := ctrstats .GetContainerStats (context .Background (), c )
50
+ var statsV1 * v1.Metrics
51
+ var statsV2 * v2.Metrics
52
+ var err error
53
+ if s .metricsReader .IsCgroupV2 () {
54
+ statsV2 , err = ctrstats .GetContainerStatsV2 (context .Background (), c )
55
+ } else {
56
+ statsV1 , err = ctrstats .GetContainerStatsV1 (context .Background (), c )
57
+ }
58
+
51
59
if err != nil {
52
60
log .V (10 ).WithValues (
53
61
"container" , c .ContainerID ,
54
62
).Info ("failed to get container stats - likely an issue with non-running containers being tracked in containerd state" , "err" , err )
55
- } else if stats != nil {
56
- cpu , err := cmStatsToCPUResult (stats , readTime )
63
+ } else if statsV1 != nil || statsV2 != nil {
64
+ var cpu containerCPUMetrics
65
+ if statsV1 != nil {
66
+ cpu , err = cmStatsToCPUResultV1 (statsV1 , readTime )
67
+ } else if statsV2 != nil {
68
+ cpu , err = cmStatsToCPUResultV2 (statsV2 , readTime )
69
+ }
57
70
if err != nil {
58
71
log .Error (err , "no cpu stats available for container" ,
59
72
"namespace" , c .NamespaceName ,
60
73
"pod" , c .PodName ,
61
74
"container" , c .ContainerName ,
62
75
)
63
76
}
64
- mem , err := cmStatsToMemoryResult (stats , readTime )
77
+
78
+ var mem containerMemoryMetrics
79
+ if statsV1 != nil {
80
+ mem , err = cmStatsToMemoryResultV1 (statsV1 , readTime )
81
+
82
+ } else if statsV2 != nil {
83
+ mem , err = cmStatsToMemoryResultV2 (statsV2 , readTime )
84
+ }
65
85
if err != nil {
66
86
log .Error (err , "no memory stats available for container" ,
67
87
"namespace" , c .NamespaceName ,
@@ -87,16 +107,15 @@ func (s *sampleCache) getContainerCPUAndMemoryCM() (cpuMetrics, memoryMetrics, e
87
107
return cpuResult , memResult , nil
88
108
}
89
109
90
- // cmStatsToCPUResult converts cpu stats read from containerd into a compatible type.
91
- func cmStatsToCPUResult (stats * v1.Metrics , readTime time.Time ) (containerCPUMetrics , error ) {
110
+ // cmStatsToCPUResultV1 converts cpu stats read from containerd into a compatible type.
111
+ func cmStatsToCPUResultV1 (stats * v1.Metrics , readTime time.Time ) (containerCPUMetrics , error ) {
92
112
metrics := containerCPUMetrics {}
93
113
if stats .CPU == nil {
94
114
err := errors .New ("no cpu stats available" )
95
115
return metrics , err
96
116
}
97
117
98
118
metrics .usage .Time = readTime
99
- // TODO: I assume we want usage.total but kernel/user breakouts are also available
100
119
metrics .usage .UsageNanoSec = stats .CPU .Usage .Total
101
120
102
121
metrics .throttling .Time = readTime
@@ -107,22 +126,38 @@ func cmStatsToCPUResult(stats *v1.Metrics, readTime time.Time) (containerCPUMetr
107
126
return metrics , nil
108
127
}
109
128
110
- // cmStatsToMemoryResult converts memory stats read from containerd into a compatible type.
111
- func cmStatsToMemoryResult (stats * v1.Metrics , readTime time.Time ) (containerMemoryMetrics , error ) {
129
+ // cmStatsToCPUResultV2 converts cpu stats read from containerd into a compatible type.
130
+ func cmStatsToCPUResultV2 (stats * v2.Metrics , readTime time.Time ) (containerCPUMetrics , error ) {
131
+ metrics := containerCPUMetrics {}
132
+ if stats .CPU == nil {
133
+ err := errors .New ("no cpu stats available" )
134
+ return metrics , err
135
+ }
136
+
137
+ metrics .usage .Time = readTime
138
+ metrics .usage .UsageNanoSec = stats .CPU .UsageUsec * 1000 // convert usec to nanosec
139
+
140
+ metrics .throttling .Time = readTime
141
+ metrics .throttling .ThrottledNanoSec = stats .CPU .ThrottledUsec * 1000 // convert usec to nanosec
142
+ metrics .throttling .ThrottledPeriods = stats .CPU .NrThrottled
143
+ metrics .throttling .TotalPeriods = stats .CPU .NrPeriods
144
+
145
+ return metrics , nil
146
+ }
147
+
148
+ // cmStatsToMemoryResultV1 converts memory stats read from containerd into a compatible type.
149
+ func cmStatsToMemoryResultV1 (stats * v1.Metrics , readTime time.Time ) (containerMemoryMetrics , error ) {
112
150
metrics := containerMemoryMetrics {}
113
151
if stats .Memory == nil {
114
152
err := errors .New ("no memory stats available" )
115
153
return metrics , err
116
154
}
117
155
118
156
metrics .Time = readTime
119
- // NOTE: RSSHuge, MappedFiles, pgfaults, (in)active anon, etc. also available
120
- // TODO: should this be Total{RSS,Cache} or is this fine?
121
157
metrics .RSS = stats .Memory .RSS
122
158
metrics .Cache = stats .Memory .Cache
123
159
124
160
if stats .MemoryOomControl != nil {
125
- // TODO: not sure if these are the right metrics?
126
161
metrics .OOMKills = stats .MemoryOomControl .OomKill
127
162
metrics .OOMs = stats .MemoryOomControl .UnderOom
128
163
} else {
@@ -131,3 +166,24 @@ func cmStatsToMemoryResult(stats *v1.Metrics, readTime time.Time) (containerMemo
131
166
132
167
return metrics , nil
133
168
}
169
+
170
+ // cmStatsToMemoryResultV2 converts memory stats read from containerd into a compatible type.
171
+ func cmStatsToMemoryResultV2 (stats * v2.Metrics , readTime time.Time ) (containerMemoryMetrics , error ) {
172
+ metrics := containerMemoryMetrics {}
173
+ if stats .Memory == nil {
174
+ err := errors .New ("no memory stats available" )
175
+ return metrics , err
176
+ }
177
+
178
+ metrics .Time = readTime
179
+ metrics .Current = stats .Memory .Usage
180
+
181
+ if stats .MemoryEvents != nil {
182
+ metrics .OOMKills = stats .MemoryEvents .OomKill
183
+ metrics .OOMs = stats .MemoryEvents .Oom
184
+ } else {
185
+ log .V (10 ).Info ("no OOM stats available" )
186
+ }
187
+
188
+ return metrics , nil
189
+ }
0 commit comments