github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/processors/rate_calculator.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 processors 16 17 import ( 18 "k8s.io/heapster/metrics/core" 19 20 "github.com/golang/glog" 21 ) 22 23 type RateCalculator struct { 24 rateMetricsMapping map[string]core.Metric 25 previousBatch *core.DataBatch 26 } 27 28 func (this *RateCalculator) Name() string { 29 return "rate calculator" 30 } 31 32 func (this *RateCalculator) Process(batch *core.DataBatch) (*core.DataBatch, error) { 33 if this.previousBatch == nil { 34 glog.V(4).Infof("Skipping rate calculation entirely - no previous batch found") 35 this.previousBatch = batch 36 return batch, nil 37 } 38 if !batch.Timestamp.After(this.previousBatch.Timestamp) { 39 // something got out of sync, do nothing. 40 glog.Errorf("New data batch has timestamp before the previous one: new:%v old:%v", batch.Timestamp, this.previousBatch.Timestamp) 41 return batch, nil 42 } 43 44 for key, newMs := range batch.MetricSets { 45 oldMs, found := this.previousBatch.MetricSets[key] 46 if !found { 47 continue 48 } 49 if !newMs.ScrapeTime.After(oldMs.ScrapeTime) { 50 // New must be strictly after old. 51 glog.V(4).Infof("Skipping rate calculations for %s - new batch (%s) was not scraped strictly after old batch (%s)", key, newMs.ScrapeTime, oldMs.ScrapeTime) 52 continue 53 } 54 if !newMs.CollectionStartTime.Equal(oldMs.CollectionStartTime) { 55 glog.V(4).Infof("Skipping rates for %s - different collection start time new:%v old:%v", key, newMs.CollectionStartTime, oldMs.CollectionStartTime) 56 // Create time for container must be the same. 57 continue 58 } 59 60 var metricValNew, metricValOld core.MetricValue 61 var foundNew, foundOld bool 62 63 for metricName, targetMetric := range this.rateMetricsMapping { 64 if metricName == core.MetricDiskIORead.MetricDescriptor.Name || metricName == core.MetricDiskIOWrite.MetricDescriptor.Name { 65 for _, itemNew := range newMs.LabeledMetrics { 66 foundNew, foundOld = false, false 67 if itemNew.Name == metricName { 68 metricValNew, foundNew = itemNew.MetricValue, true 69 for _, itemOld := range oldMs.LabeledMetrics { 70 // Fix negative value on "disk/io_read_bytes_rate" and "disk/io_write_bytes_rate" when multiple disk devices are available 71 if itemOld.Name == metricName && itemOld.Labels[core.LabelResourceID.Key] == itemNew.Labels[core.LabelResourceID.Key] { 72 metricValOld, foundOld = itemOld.MetricValue, true 73 break 74 } 75 } 76 } 77 78 if foundNew && foundOld { 79 if targetMetric.MetricDescriptor.ValueType == core.ValueFloat { 80 newVal := 1e9 * float64(metricValNew.IntValue-metricValOld.IntValue) / 81 float64(newMs.ScrapeTime.UnixNano()-oldMs.ScrapeTime.UnixNano()) 82 83 newMs.LabeledMetrics = append(newMs.LabeledMetrics, core.LabeledMetric{ 84 Name: targetMetric.MetricDescriptor.Name, 85 Labels: itemNew.Labels, 86 MetricValue: core.MetricValue{ 87 ValueType: core.ValueFloat, 88 MetricType: core.MetricGauge, 89 FloatValue: newVal, 90 }, 91 }) 92 } 93 } else if foundNew && !foundOld || !foundNew && foundOld { 94 glog.V(4).Infof("Skipping rates for %s in %s: metric not found in one of old (%v) or new (%v)", metricName, key, foundOld, foundNew) 95 } 96 } 97 } else { 98 metricValNew, foundNew = newMs.MetricValues[metricName] 99 metricValOld, foundOld = oldMs.MetricValues[metricName] 100 101 if foundNew && foundOld && metricName == core.MetricCpuUsage.MetricDescriptor.Name { 102 // cpu/usage values are in nanoseconds; we want to have it in millicores (that's why constant 1000 is here). 103 newVal := 1000 * (metricValNew.IntValue - metricValOld.IntValue) / 104 (newMs.ScrapeTime.UnixNano() - oldMs.ScrapeTime.UnixNano()) 105 106 newMs.MetricValues[targetMetric.MetricDescriptor.Name] = core.MetricValue{ 107 ValueType: core.ValueInt64, 108 MetricType: core.MetricGauge, 109 IntValue: newVal, 110 } 111 112 } else if foundNew && foundOld && targetMetric.MetricDescriptor.ValueType == core.ValueFloat { 113 newVal := 1e9 * float64(metricValNew.IntValue-metricValOld.IntValue) / 114 float64(newMs.ScrapeTime.UnixNano()-oldMs.ScrapeTime.UnixNano()) 115 116 newMs.MetricValues[targetMetric.MetricDescriptor.Name] = core.MetricValue{ 117 ValueType: core.ValueFloat, 118 MetricType: core.MetricGauge, 119 FloatValue: newVal, 120 } 121 } else if foundNew && !foundOld || !foundNew && foundOld { 122 glog.V(4).Infof("Skipping rates for %s in %s: metric not found in one of old (%v) or new (%v)", metricName, key, foundOld, foundNew) 123 } 124 } 125 } 126 } 127 this.previousBatch = batch 128 return batch, nil 129 } 130 131 func NewRateCalculator(metrics map[string]core.Metric) *RateCalculator { 132 return &RateCalculator{ 133 rateMetricsMapping: metrics, 134 } 135 }