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 }