go.etcd.io/etcd@v3.3.27+incompatible/proxy/grpcproxy/metrics.go (about)

     1  // Copyright 2016 The etcd Authors
     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 grpcproxy
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"math/rand"
    21  	"net/http"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/coreos/etcd/etcdserver/api/etcdhttp"
    26  	"github.com/prometheus/client_golang/prometheus"
    27  )
    28  
    29  var (
    30  	watchersCoalescing = prometheus.NewGauge(prometheus.GaugeOpts{
    31  		Namespace: "etcd",
    32  		Subsystem: "grpc_proxy",
    33  		Name:      "watchers_coalescing_total",
    34  		Help:      "Total number of current watchers coalescing",
    35  	})
    36  	eventsCoalescing = prometheus.NewCounter(prometheus.CounterOpts{
    37  		Namespace: "etcd",
    38  		Subsystem: "grpc_proxy",
    39  		Name:      "events_coalescing_total",
    40  		Help:      "Total number of events coalescing",
    41  	})
    42  	cacheKeys = prometheus.NewGauge(prometheus.GaugeOpts{
    43  		Namespace: "etcd",
    44  		Subsystem: "grpc_proxy",
    45  		Name:      "cache_keys_total",
    46  		Help:      "Total number of keys/ranges cached",
    47  	})
    48  	cacheHits = prometheus.NewGauge(prometheus.GaugeOpts{
    49  		Namespace: "etcd",
    50  		Subsystem: "grpc_proxy",
    51  		Name:      "cache_hits_total",
    52  		Help:      "Total number of cache hits",
    53  	})
    54  	cachedMisses = prometheus.NewGauge(prometheus.GaugeOpts{
    55  		Namespace: "etcd",
    56  		Subsystem: "grpc_proxy",
    57  		Name:      "cache_misses_total",
    58  		Help:      "Total number of cache misses",
    59  	})
    60  )
    61  
    62  func init() {
    63  	prometheus.MustRegister(watchersCoalescing)
    64  	prometheus.MustRegister(eventsCoalescing)
    65  	prometheus.MustRegister(cacheKeys)
    66  	prometheus.MustRegister(cacheHits)
    67  	prometheus.MustRegister(cachedMisses)
    68  }
    69  
    70  // HandleMetrics performs a GET request against etcd endpoint and returns '/metrics'.
    71  func HandleMetrics(mux *http.ServeMux, c *http.Client, eps []string) {
    72  	// random shuffle endpoints
    73  	r := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
    74  	if len(eps) > 1 {
    75  		eps = shuffleEndpoints(r, eps)
    76  	}
    77  
    78  	pathMetrics := etcdhttp.PathMetrics
    79  	mux.HandleFunc(pathMetrics, func(w http.ResponseWriter, r *http.Request) {
    80  		target := fmt.Sprintf("%s%s", eps[0], pathMetrics)
    81  		if !strings.HasPrefix(target, "http") {
    82  			scheme := "http"
    83  			if r.TLS != nil {
    84  				scheme = "https"
    85  			}
    86  			target = fmt.Sprintf("%s://%s", scheme, target)
    87  		}
    88  
    89  		resp, err := c.Get(target)
    90  		if err != nil {
    91  			http.Error(w, "Internal server error", http.StatusInternalServerError)
    92  			return
    93  		}
    94  		defer resp.Body.Close()
    95  		w.Header().Set("Content-Type", "text/plain; version=0.0.4")
    96  		body, _ := ioutil.ReadAll(resp.Body)
    97  		fmt.Fprintf(w, "%s", body)
    98  	})
    99  }
   100  
   101  func shuffleEndpoints(r *rand.Rand, eps []string) []string {
   102  	// copied from Go 1.9<= rand.Rand.Perm
   103  	n := len(eps)
   104  	p := make([]int, n)
   105  	for i := 0; i < n; i++ {
   106  		j := r.Intn(i + 1)
   107  		p[i] = p[j]
   108  		p[j] = i
   109  	}
   110  	neps := make([]string, n)
   111  	for i, k := range p {
   112  		neps[i] = eps[k]
   113  	}
   114  	return neps
   115  }