github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/sinks/statsd/driver.go (about) 1 // Copyright 2016 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 statsd 16 17 import ( 18 "fmt" 19 "github.com/golang/glog" 20 "k8s.io/heapster/metrics/core" 21 "net/url" 22 "strconv" 23 "strings" 24 "sync" 25 ) 26 27 const ( 28 defaultHost = "localhost:8125" 29 defaultNumMetricsPerMsg = 5 30 defaultProtocolType = "etsystatsd" 31 ) 32 33 type statsdSink struct { 34 config statsdConfig 35 formatter Formatter 36 client statsdClient 37 sync.RWMutex 38 } 39 40 type statsdConfig struct { 41 host string 42 prefix string 43 numMetricsPerMsg int 44 protocolType string 45 renameLabels map[string]string 46 allowedLabels map[string]string 47 customizeLabel CustomizeLabel 48 } 49 50 func getConfig(uri *url.URL) (cfg statsdConfig, err error) { 51 config := statsdConfig{ 52 host: defaultHost, 53 prefix: "", 54 numMetricsPerMsg: defaultNumMetricsPerMsg, 55 protocolType: defaultProtocolType, 56 renameLabels: make(map[string]string), 57 allowedLabels: make(map[string]string), 58 customizeLabel: nil, 59 } 60 61 if len(uri.Host) > 0 { 62 config.host = uri.Host 63 } 64 opts := uri.Query() 65 if len(opts["numMetricsPerMsg"]) >= 1 { 66 val, err := strconv.Atoi(opts["numMetricsPerMsg"][0]) 67 if err != nil { 68 return config, fmt.Errorf("failed to parse `numMetricsPerMsg` field - %v", err) 69 } 70 config.numMetricsPerMsg = val 71 } 72 if len(opts["protocolType"]) >= 1 { 73 config.protocolType = strings.ToLower(opts["protocolType"][0]) 74 } 75 if len(opts["prefix"]) >= 1 { 76 config.prefix = opts["prefix"][0] 77 } 78 if len(opts["renameLabels"]) >= 1 { 79 renameLabels := strings.Split(opts["renameLabels"][0], ",") 80 for _, renameLabel := range renameLabels { 81 kv := strings.SplitN(renameLabel, ":", 2) 82 config.renameLabels[kv[0]] = kv[1] 83 } 84 } 85 if len(opts["allowedLabels"]) >= 1 { 86 allowedLabels := strings.Split(opts["allowedLabels"][0], ",") 87 for _, allowedLabel := range allowedLabels { 88 config.allowedLabels[allowedLabel] = allowedLabel 89 } 90 } 91 labelStyle := DefaultLabelStyle 92 if len(opts["labelStyle"]) >= 1 { 93 switch opts["labelStyle"][0] { 94 case "lowerCamelCase": 95 labelStyle = SnakeToLowerCamel 96 case "upperCamelCase": 97 labelStyle = SnakeToUpperCamel 98 default: 99 glog.Errorf("invalid labelStyle - %s", opts["labelStyle"][0]) 100 } 101 } 102 labelCustomizer := LabelCustomizer{config.renameLabels, labelStyle} 103 config.customizeLabel = labelCustomizer.Customize 104 glog.Infof("statsd metrics sink using configuration : %+v", config) 105 return config, nil 106 } 107 108 func (sink *statsdSink) ExportData(dataBatch *core.DataBatch) { 109 sink.Lock() 110 defer sink.Unlock() 111 112 var metrics []string 113 var tmpstr string 114 var err error 115 allowAllLabels := len(sink.config.allowedLabels) == 0 116 for _, metricSet := range dataBatch.MetricSets { 117 var metricSetLabels map[string]string 118 if allowAllLabels { 119 metricSetLabels = metricSet.Labels 120 } else { 121 metricSetLabels = make(map[string]string) 122 for k, v := range metricSet.Labels { 123 _, allowed := sink.config.allowedLabels[k] 124 if allowed { 125 metricSetLabels[k] = v 126 } 127 } 128 } 129 for metricName, metricValue := range metricSet.MetricValues { 130 tmpstr, err = sink.formatter.Format(sink.config.prefix, metricName, metricSetLabels, sink.config.customizeLabel, metricValue) 131 if err != nil { 132 glog.Errorf("statsd metrics sink - failed to format metrics : %s", err.Error()) 133 continue 134 } 135 metrics = append(metrics, tmpstr) 136 } 137 for _, metric := range metricSet.LabeledMetrics { 138 labels := make(map[string]string) 139 for k, v := range metricSetLabels { 140 labels[k] = v 141 } 142 for k, v := range metric.Labels { 143 _, allowed := sink.config.allowedLabels[k] 144 if allowed || allowAllLabels { 145 labels[k] = v 146 } 147 } 148 tmpstr, err = sink.formatter.Format(sink.config.prefix, metric.Name, labels, sink.config.customizeLabel, metric.MetricValue) 149 if err != nil { 150 glog.Errorf("statsd metrics sink - failed to format labeled metrics : %v", err) 151 continue 152 } 153 metrics = append(metrics, tmpstr) 154 } 155 } 156 glog.V(5).Infof("Sending metrics --- %s", metrics) 157 err = sink.client.send(metrics) 158 if err != nil { 159 glog.Errorf("statsd metrics sink - failed to send some metrics : %v", err) 160 } 161 } 162 163 func (sink *statsdSink) Name() string { 164 return "StatsD Sink" 165 } 166 167 func (sink *statsdSink) Stop() { 168 glog.V(2).Info("statsd metrics sink is stopping") 169 sink.client.close() 170 } 171 172 func NewStatsdSinkWithClient(uri *url.URL, client statsdClient) (sink core.DataSink, err error) { 173 config, err := getConfig(uri) 174 if err != nil { 175 return nil, err 176 } 177 formatter, err := NewFormatter(config.protocolType) 178 if err != nil { 179 return nil, err 180 } 181 glog.V(2).Info("statsd metrics sink is created") 182 return &statsdSink{ 183 config: config, 184 formatter: formatter, 185 client: client, 186 }, nil 187 } 188 189 func NewStatsdSink(uri *url.URL) (sink core.DataSink, err error) { 190 config, err := getConfig(uri) 191 if err != nil { 192 return nil, err 193 } 194 client, err := NewStatsdClient(config.host, config.numMetricsPerMsg) 195 if err != nil { 196 return nil, err 197 } 198 return NewStatsdSinkWithClient(uri, client) 199 }