github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/sinks/librato/librato.go (about)

     1  // Copyright 2017 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 librato
    16  
    17  import (
    18  	"net/url"
    19  	"regexp"
    20  	"strings"
    21  	"sync"
    22  	"time"
    23  
    24  	librato_common "k8s.io/heapster/common/librato"
    25  	"k8s.io/heapster/metrics/core"
    26  
    27  	"github.com/golang/glog"
    28  )
    29  
    30  type libratoSink struct {
    31  	client librato_common.Client
    32  	sync.RWMutex
    33  	c librato_common.LibratoConfig
    34  }
    35  
    36  const (
    37  	// Value Field name
    38  	valueField = "value"
    39  
    40  	// Maximum number of librato measurements to be sent in one batch.
    41  	maxSendBatchSize = 1000
    42  
    43  	// Librato measurement restrictions
    44  	// https://www.librato.com/docs/api/#measurement-restrictions
    45  	maxMeasurementNameLength = 255
    46  	maxTagNameLength         = 64
    47  	maxTagValueLength        = 255
    48  )
    49  
    50  var (
    51  	// Librato measurement restrictions
    52  	// https://www.librato.com/docs/api/#measurement-restrictions
    53  	invalidMeasurementNameRegexp = regexp.MustCompile("[^A-Za-z0-9.:-_]")
    54  	invalidTagNameRegex          = regexp.MustCompile("[^-.:_\\w]")
    55  	invalidTagValueRegex         = regexp.MustCompile("[^-.:_\\w ]")
    56  )
    57  
    58  func (sink *libratoSink) formatMeasurementName(metricName string) string {
    59  	measurementName := strings.Replace(metricName, "/", ".", -1)
    60  	name := sink.c.Prefix + measurementName
    61  
    62  	return sink.trunc(invalidMeasurementNameRegexp.ReplaceAllString(name, "_"), maxMeasurementNameLength)
    63  }
    64  
    65  func (sink *libratoSink) formatTagName(tagName string) string {
    66  	return sink.trunc(invalidTagNameRegex.ReplaceAllString(tagName, "_"), maxTagNameLength)
    67  }
    68  
    69  func (sink *libratoSink) formatTagValue(tagName string) string {
    70  	return sink.trunc(invalidTagValueRegex.ReplaceAllString(tagName, "_"), maxTagValueLength)
    71  }
    72  
    73  func (sink *libratoSink) trunc(val string, length int) string {
    74  	if len(val) <= length {
    75  		return val
    76  	}
    77  
    78  	return val[:length]
    79  }
    80  
    81  func (sink *libratoSink) ExportData(dataBatch *core.DataBatch) {
    82  	sink.Lock()
    83  	defer sink.Unlock()
    84  
    85  	measurements := make([]librato_common.Measurement, 0, 0)
    86  	for _, metricSet := range dataBatch.MetricSets {
    87  		for metricName, metricValue := range metricSet.MetricValues {
    88  
    89  			var value float64
    90  			if core.ValueInt64 == metricValue.ValueType {
    91  				value = float64(metricValue.IntValue)
    92  			} else if core.ValueFloat == metricValue.ValueType {
    93  				value = float64(metricValue.FloatValue)
    94  			} else {
    95  				continue
    96  			}
    97  
    98  			name := sink.formatMeasurementName(metricName)
    99  			measurement := librato_common.Measurement{
   100  				Name:  name,
   101  				Tags:  make(map[string]string),
   102  				Time:  dataBatch.Timestamp.Unix(),
   103  				Value: value,
   104  			}
   105  
   106  			for key, value := range metricSet.Labels {
   107  				measurement.Tags[sink.formatTagName(key)] = sink.formatTagValue(value)
   108  			}
   109  
   110  			measurements = append(measurements, measurement)
   111  			if len(measurements) >= maxSendBatchSize {
   112  				sink.sendData(measurements)
   113  				measurements = make([]librato_common.Measurement, 0, 0)
   114  			}
   115  		}
   116  
   117  		for _, labeledMetric := range metricSet.LabeledMetrics {
   118  
   119  			var value float64
   120  			if core.ValueInt64 == labeledMetric.ValueType {
   121  				value = float64(labeledMetric.IntValue)
   122  			} else if core.ValueFloat == labeledMetric.ValueType {
   123  				value = float64(labeledMetric.FloatValue)
   124  			} else {
   125  				continue
   126  			}
   127  
   128  			// Prepare measurement without fields
   129  			name := sink.formatMeasurementName(labeledMetric.Name)
   130  			measurement := librato_common.Measurement{
   131  				Name:  name,
   132  				Tags:  make(map[string]string),
   133  				Time:  dataBatch.Timestamp.Unix(),
   134  				Value: value,
   135  			}
   136  			for key, value := range metricSet.Labels {
   137  				measurement.Tags[sink.formatTagName(key)] = sink.formatTagValue(value)
   138  			}
   139  			for key, value := range labeledMetric.Labels {
   140  				measurement.Tags[sink.formatTagName(key)] = sink.formatTagValue(value)
   141  			}
   142  
   143  			measurements = append(measurements, measurement)
   144  			if len(measurements) >= maxSendBatchSize {
   145  				sink.sendData(measurements)
   146  				measurements = make([]librato_common.Measurement, 0, 0)
   147  			}
   148  		}
   149  	}
   150  	if len(measurements) >= 0 {
   151  		sink.sendData(measurements)
   152  	}
   153  }
   154  
   155  func (sink *libratoSink) sendData(measurements []librato_common.Measurement) {
   156  	start := time.Now()
   157  	if err := sink.client.Write(measurements); err != nil {
   158  		glog.Errorf("Librato write failed: %v", err)
   159  	}
   160  	end := time.Now()
   161  	glog.V(4).Infof("Exported %d data to librato in %s", len(measurements), end.Sub(start))
   162  }
   163  
   164  func (sink *libratoSink) Name() string {
   165  	return "Librato Sink"
   166  }
   167  
   168  func (sink *libratoSink) Stop() {
   169  	// nothing needs to be done.
   170  }
   171  
   172  func CreateLibratoSink(uri *url.URL) (core.DataSink, error) {
   173  	config, err := librato_common.BuildConfig(uri)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	client := librato_common.NewClient(*config)
   178  	sink := &libratoSink{
   179  		client: client,
   180  		c:      *config,
   181  	}
   182  	glog.Infof("created librato sink with options: user:%s", config.Username)
   183  	return sink, nil
   184  }