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  }