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  }