github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/api/v1/api.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package v1 16 17 import ( 18 "time" 19 20 restful "github.com/emicklei/go-restful" 21 "github.com/golang/glog" 22 23 "k8s.io/heapster/metrics/api/v1/types" 24 "k8s.io/heapster/metrics/core" 25 metricsink "k8s.io/heapster/metrics/sinks/metric" 26 ) 27 28 type Api struct { 29 runningInKubernetes bool 30 metricSink *metricsink.MetricSink 31 historicalSource core.HistoricalSource 32 gkeMetrics map[string]core.MetricDescriptor 33 gkeLabels map[string]core.LabelDescriptor 34 disabled bool 35 } 36 37 var ( 38 emptyMetricsResponse = make([]*types.Timeseries, 0) 39 ) 40 41 // Create a new Api to serve from the specified cache. 42 func NewApi(runningInKubernetes bool, metricSink *metricsink.MetricSink, historicalSource core.HistoricalSource, disableMetricExport bool) *Api { 43 gkeMetrics := make(map[string]core.MetricDescriptor) 44 gkeLabels := make(map[string]core.LabelDescriptor) 45 for _, val := range core.StandardMetrics { 46 gkeMetrics[val.Name] = val.MetricDescriptor 47 } 48 for _, val := range core.LabeledMetrics { 49 gkeMetrics[val.Name] = val.MetricDescriptor 50 } 51 gkeMetrics[core.MetricCpuLimit.Name] = core.MetricCpuLimit.MetricDescriptor 52 gkeMetrics[core.MetricMemoryLimit.Name] = core.MetricMemoryLimit.MetricDescriptor 53 54 for _, val := range core.CommonLabels() { 55 gkeLabels[val.Key] = val 56 } 57 for _, val := range core.ContainerLabels() { 58 gkeLabels[val.Key] = val 59 } 60 for _, val := range core.PodLabels() { 61 gkeLabels[val.Key] = val 62 } 63 64 return &Api{ 65 runningInKubernetes: runningInKubernetes, 66 metricSink: metricSink, 67 historicalSource: historicalSource, 68 gkeMetrics: gkeMetrics, 69 gkeLabels: gkeLabels, 70 disabled: disableMetricExport, 71 } 72 } 73 74 // Register the mainApi on the specified endpoint. 75 func (a *Api) Register(container *restful.Container) { 76 ws := new(restful.WebService) 77 ws.Path("/api/v1/metric-export"). 78 Doc("Exports the latest point for all Heapster metrics"). 79 Produces(restful.MIME_JSON) 80 ws.Route(ws.GET(""). 81 To(a.exportMetrics). 82 Doc("export the latest data point for all metrics"). 83 Operation("exportMetrics"). 84 Writes([]*types.Timeseries{})) 85 container.Add(ws) 86 ws = new(restful.WebService) 87 ws.Path("/api/v1/metric-export-schema"). 88 Doc("Schema for metrics exported by heapster"). 89 Produces(restful.MIME_JSON) 90 ws.Route(ws.GET(""). 91 To(a.exportMetricsSchema). 92 Doc("export the schema for all metrics"). 93 Operation("exportmetricsSchema"). 94 Writes(types.TimeseriesSchema{})) 95 container.Add(ws) 96 97 if a.metricSink != nil { 98 a.RegisterModel(container) 99 } 100 101 if a.historicalSource != nil { 102 a.RegisterHistorical(container) 103 } 104 } 105 106 func convertLabelDescriptor(ld core.LabelDescriptor) types.LabelDescriptor { 107 return types.LabelDescriptor{ 108 Key: ld.Key, 109 Description: ld.Description, 110 } 111 } 112 113 func convertMetricDescriptor(md core.MetricDescriptor) types.MetricDescriptor { 114 result := types.MetricDescriptor{ 115 Name: md.Name, 116 Description: md.Description, 117 Labels: make([]types.LabelDescriptor, 0, len(md.Labels)), 118 } 119 for _, label := range md.Labels { 120 result.Labels = append(result.Labels, convertLabelDescriptor(label)) 121 } 122 123 switch md.Type { 124 case core.MetricCumulative: 125 result.Type = "cumulative" 126 case core.MetricGauge: 127 result.Type = "gauge" 128 case core.MetricDelta: 129 result.Type = "delta" 130 } 131 132 switch md.ValueType { 133 case core.ValueInt64: 134 result.ValueType = "int64" 135 case core.ValueFloat: 136 result.ValueType = "double" 137 } 138 139 switch md.Units { 140 case core.UnitsBytes: 141 result.Units = "bytes" 142 case core.UnitsMilliseconds: 143 result.Units = "ms" 144 case core.UnitsNanoseconds: 145 result.Units = "ns" 146 case core.UnitsMillicores: 147 result.Units = "millicores" 148 } 149 return result 150 } 151 152 func (a *Api) exportMetricsSchema(_ *restful.Request, response *restful.Response) { 153 result := types.TimeseriesSchema{ 154 Metrics: make([]types.MetricDescriptor, 0), 155 CommonLabels: make([]types.LabelDescriptor, 0), 156 PodLabels: make([]types.LabelDescriptor, 0), 157 } 158 for _, metric := range core.StandardMetrics { 159 if _, found := a.gkeMetrics[metric.Name]; found { 160 result.Metrics = append(result.Metrics, convertMetricDescriptor(metric.MetricDescriptor)) 161 } 162 } 163 for _, metric := range core.AdditionalMetrics { 164 if _, found := a.gkeMetrics[metric.Name]; found { 165 result.Metrics = append(result.Metrics, convertMetricDescriptor(metric.MetricDescriptor)) 166 } 167 } 168 for _, metric := range core.LabeledMetrics { 169 if _, found := a.gkeMetrics[metric.Name]; found { 170 result.Metrics = append(result.Metrics, convertMetricDescriptor(metric.MetricDescriptor)) 171 } 172 } 173 174 for _, label := range core.CommonLabels() { 175 if _, found := a.gkeLabels[label.Key]; found { 176 result.CommonLabels = append(result.CommonLabels, convertLabelDescriptor(label)) 177 } 178 } 179 for _, label := range core.ContainerLabels() { 180 if _, found := a.gkeLabels[label.Key]; found { 181 result.CommonLabels = append(result.CommonLabels, convertLabelDescriptor(label)) 182 } 183 } 184 for _, label := range core.PodLabels() { 185 if _, found := a.gkeLabels[label.Key]; found { 186 result.PodLabels = append(result.PodLabels, convertLabelDescriptor(label)) 187 } 188 } 189 response.WriteEntity(result) 190 } 191 192 func (a *Api) exportMetrics(_ *restful.Request, response *restful.Response) { 193 response.PrettyPrint(false) 194 err := response.WriteEntity(a.getMetricsResponse()) 195 if err != nil { 196 glog.V(4).Infof("Error writing response: %v", err) 197 } 198 } 199 200 func (a *Api) getMetricsResponse() []*types.Timeseries { 201 if a.disabled { 202 return emptyMetricsResponse 203 } else { 204 return a.processMetricsRequest(a.metricSink.GetShortStore()) 205 } 206 } 207 208 func (a *Api) processMetricsRequest(shortStorage []*core.DataBatch) []*types.Timeseries { 209 tsmap := make(map[string]*types.Timeseries) 210 211 var newestBatch *core.DataBatch 212 for _, batch := range shortStorage { 213 if newestBatch == nil || newestBatch.Timestamp.Before(batch.Timestamp) { 214 newestBatch = batch 215 } 216 } 217 218 var timeseries []*types.Timeseries 219 if newestBatch == nil { 220 return timeseries 221 } 222 for key, ms := range newestBatch.MetricSets { 223 ts := tsmap[key] 224 225 msType := ms.Labels[core.LabelMetricSetType.Key] 226 227 switch msType { 228 case core.MetricSetTypeNode, core.MetricSetTypePod, core.MetricSetTypePodContainer, core.MetricSetTypeSystemContainer: 229 default: 230 continue 231 } 232 233 if ts == nil { 234 ts = &types.Timeseries{ 235 Metrics: make(map[string][]types.Point), 236 Labels: make(map[string]string), 237 } 238 for labelName, labelValue := range ms.Labels { 239 if _, ok := a.gkeLabels[labelName]; ok { 240 ts.Labels[labelName] = labelValue 241 } 242 } 243 if msType == core.MetricSetTypeNode { 244 ts.Labels[core.LabelContainerName.Key] = "machine" 245 } 246 if msType == core.MetricSetTypePod { 247 ts.Labels[core.LabelContainerName.Key] = "/pod" 248 } 249 tsmap[key] = ts 250 } 251 for metricName, metricVal := range ms.MetricValues { 252 if _, ok := a.gkeMetrics[metricName]; ok { 253 processPoint(ts, newestBatch, metricName, &metricVal, nil, ms.CollectionStartTime) 254 } 255 } 256 for _, metric := range ms.LabeledMetrics { 257 if _, ok := a.gkeMetrics[metric.Name]; ok { 258 processPoint(ts, newestBatch, metric.Name, &metric.MetricValue, metric.Labels, ms.CollectionStartTime) 259 } 260 } 261 } 262 timeseries = make([]*types.Timeseries, 0, len(tsmap)) 263 for _, ts := range tsmap { 264 timeseries = append(timeseries, ts) 265 } 266 return timeseries 267 } 268 269 func processPoint(ts *types.Timeseries, db *core.DataBatch, metricName string, metricVal *core.MetricValue, labels map[string]string, creationTime time.Time) { 270 points := ts.Metrics[metricName] 271 if points == nil { 272 points = make([]types.Point, 0, 1) 273 } 274 point := types.Point{ 275 Start: db.Timestamp, 276 End: db.Timestamp, 277 } 278 // For cumulative metric use the provided start time. 279 if metricVal.MetricType == core.MetricCumulative { 280 point.Start = creationTime 281 } 282 var value interface{} 283 if metricVal.ValueType == core.ValueInt64 { 284 value = metricVal.IntValue 285 } else if metricVal.ValueType == core.ValueFloat { 286 value = metricVal.FloatValue 287 } else { 288 return 289 } 290 point.Value = value 291 if labels != nil { 292 point.Labels = make(map[string]string) 293 for key, value := range labels { 294 point.Labels[key] = value 295 } 296 } 297 points = append(points, point) 298 ts.Metrics[metricName] = points 299 }