github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/sinks/graphite/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 graphite 16 17 import ( 18 "fmt" 19 "net" 20 "net/url" 21 "strconv" 22 "strings" 23 "sync" 24 25 "k8s.io/heapster/metrics/core" 26 27 "github.com/golang/glog" 28 "github.com/marpaia/graphite-golang" 29 ) 30 31 const ( 32 DefaultHost = "localhost" 33 DefaultPort = 2003 34 DefaultPrefix = "kubernetes" 35 ) 36 37 type graphiteClient interface { 38 Connect() error 39 Disconnect() error 40 SendMetrics(metric []graphite.Metric) error 41 } 42 43 type graphiteMetric struct { 44 name string 45 value core.MetricValue 46 labels map[string]string 47 timestamp int64 48 } 49 50 var escapeFieldReplacer = strings.NewReplacer(".", "_", "/", "_") 51 52 func escapeField(f string) string { 53 return escapeFieldReplacer.Replace(f) 54 } 55 56 func (m *graphiteMetric) Path() string { 57 var metricPath string 58 if resourceId, ok := m.labels["resourceId"]; ok { 59 nameParts := strings.Split(m.name, "/") 60 section, parts := nameParts[0], nameParts[1:] 61 metricPath = strings.Join(append([]string{section, escapeField(resourceId)}, parts...), ".") 62 } else { 63 metricPath = m.name 64 } 65 metricPath = strings.Replace(metricPath, "/", ".", -1) 66 if t, ok := m.labels[core.LabelMetricSetType.Key]; ok { 67 switch t { 68 case core.MetricSetTypePodContainer: 69 return fmt.Sprintf("nodes.%s.pods.%s.%s.containers.%s.%s", 70 escapeField(m.labels[core.LabelHostname.Key]), 71 m.labels[core.LabelNamespaceName.Key], 72 escapeField(m.labels[core.LabelPodName.Key]), 73 escapeField(m.labels[core.LabelContainerName.Key]), 74 metricPath, 75 ) 76 case core.MetricSetTypeSystemContainer: 77 return fmt.Sprintf("nodes.%s.sys-containers.%s.%s", 78 escapeField(m.labels[core.LabelHostname.Key]), 79 escapeField(m.labels[core.LabelContainerName.Key]), 80 metricPath, 81 ) 82 case core.MetricSetTypePod: 83 return fmt.Sprintf("nodes.%s.pods.%s.%s.%s", 84 escapeField(m.labels[core.LabelHostname.Key]), 85 m.labels[core.LabelNamespaceName.Key], 86 escapeField(m.labels[core.LabelPodName.Key]), 87 metricPath, 88 ) 89 case core.MetricSetTypeNamespace: 90 return fmt.Sprintf("namespaces.%s.%s", 91 m.labels[core.LabelNamespaceName.Key], 92 metricPath, 93 ) 94 case core.MetricSetTypeNode: 95 return fmt.Sprintf("nodes.%s.%s", 96 escapeField(m.labels[core.LabelHostname.Key]), 97 metricPath, 98 ) 99 case core.MetricSetTypeCluster: 100 return fmt.Sprintf("cluster.%s", metricPath) 101 default: 102 glog.V(6).Infof("Unknown metric type %s", t) 103 } 104 } 105 return metricPath 106 } 107 108 func (m *graphiteMetric) Value() string { 109 switch m.value.ValueType { 110 case core.ValueInt64: 111 return fmt.Sprintf("%d", m.value.IntValue) 112 case core.ValueFloat: 113 return fmt.Sprintf("%f", m.value.FloatValue) 114 } 115 return "" 116 } 117 118 func (m *graphiteMetric) Metric() graphite.Metric { 119 return graphite.NewMetric(m.Path(), m.Value(), m.timestamp) 120 } 121 122 type Sink struct { 123 client graphiteClient 124 sync.RWMutex 125 } 126 127 func NewGraphiteSink(uri *url.URL) (core.DataSink, error) { 128 host, portString, err := net.SplitHostPort(uri.Host) 129 if err != nil { 130 return nil, err 131 } 132 if host == "" { 133 host = DefaultHost 134 } 135 port := DefaultPort 136 if portString != "" { 137 if port, err = strconv.Atoi(portString); err != nil { 138 return nil, err 139 } 140 } 141 142 prefix := uri.Query().Get("prefix") 143 if prefix == "" { 144 prefix = DefaultPrefix 145 } 146 147 client, err := graphite.GraphiteFactory(uri.Scheme, host, port, prefix) 148 if err != nil { 149 return nil, err 150 } 151 return &Sink{client: client}, nil 152 } 153 154 func (s *Sink) Name() string { 155 return "Graphite Sink" 156 } 157 158 func (s *Sink) ExportData(dataBatch *core.DataBatch) { 159 s.Lock() 160 defer s.Unlock() 161 var metrics []graphite.Metric 162 for _, metricSet := range dataBatch.MetricSets { 163 var m *graphiteMetric 164 for metricName, metricValue := range metricSet.MetricValues { 165 m = &graphiteMetric{ 166 name: metricName, 167 value: metricValue, 168 labels: metricSet.Labels, 169 timestamp: dataBatch.Timestamp.Unix(), 170 } 171 metrics = append(metrics, m.Metric()) 172 } 173 for _, metric := range metricSet.LabeledMetrics { 174 if value := metric.GetValue(); value != nil { 175 labels := make(map[string]string) 176 for k, v := range metricSet.Labels { 177 labels[k] = v 178 } 179 for k, v := range metric.Labels { 180 labels[k] = v 181 } 182 m = &graphiteMetric{ 183 name: metric.Name, 184 value: metric.MetricValue, 185 labels: labels, 186 timestamp: dataBatch.Timestamp.Unix(), 187 } 188 metrics = append(metrics, m.Metric()) 189 } 190 } 191 } 192 glog.V(8).Infof("Sending %d events to graphite", len(metrics)) 193 if err := s.client.SendMetrics(metrics); err != nil { 194 glog.V(4).Info("Graphite connection error:", err) 195 glog.V(2).Info("There were errors sending events to Graphite, reconecting") 196 s.client.Disconnect() 197 s.client.Connect() 198 } 199 } 200 201 func (s *Sink) Stop() { 202 s.client.Disconnect() 203 }