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  }