metrics.go 5.08 KB
Newer Older
Lars Gierth's avatar
Lars Gierth committed
1 2 3 4 5
package corehttp

import (
	"net"
	"net/http"
lanzafame's avatar
lanzafame committed
6
	"time"
Lars Gierth's avatar
Lars Gierth committed
7

tavit ohanian's avatar
tavit ohanian committed
8
	core "gitlab.dms3.io/dms3/go-dms3/core"
lanzafame's avatar
lanzafame committed
9 10
	"go.opencensus.io/stats/view"
	"go.opencensus.io/zpages"
Jakub Sztandera's avatar
Jakub Sztandera committed
11

lanzafame's avatar
lanzafame committed
12
	ocprom "contrib.go.opencensus.io/exporter/prometheus"
Jakub Sztandera's avatar
Jakub Sztandera committed
13 14
	prometheus "github.com/prometheus/client_golang/prometheus"
	promhttp "github.com/prometheus/client_golang/prometheus/promhttp"
Lars Gierth's avatar
Lars Gierth committed
15 16 17 18
)

// This adds the scraping endpoint which Prometheus uses to fetch metrics.
func MetricsScrapingOption(path string) ServeOption {
tavit ohanian's avatar
tavit ohanian committed
19
	return func(n *core.Dms3Node, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
20
		mux.Handle(path, promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{}))
Lars Gierth's avatar
Lars Gierth committed
21 22 23 24
		return mux, nil
	}
}

lanzafame's avatar
lanzafame committed
25 26
// This adds collection of OpenCensus metrics
func MetricsOpenCensusCollectionOption() ServeOption {
tavit ohanian's avatar
tavit ohanian committed
27
	return func(_ *core.Dms3Node, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
28
		log.Info("Init OpenCensus")
lanzafame's avatar
lanzafame committed
29 30 31

		promRegistry := prometheus.NewRegistry()
		pe, err := ocprom.NewExporter(ocprom.Options{
tavit ohanian's avatar
tavit ohanian committed
32
			Namespace: "dms3_oc",
lanzafame's avatar
lanzafame committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46
			Registry:  promRegistry,
			OnError: func(err error) {
				log.Errorw("OC ERROR", "error", err)
			},
		})
		if err != nil {
			return nil, err
		}

		// register prometheus with opencensus
		view.RegisterExporter(pe)
		view.SetReportingPeriod(2 * time.Second)

		// Construct the mux
lanzafame's avatar
lanzafame committed
47 48
		zpages.Handle(mux, "/debug/metrics/oc/debugz")
		mux.Handle("/debug/metrics/oc", pe)
lanzafame's avatar
lanzafame committed
49 50 51

		return mux, nil
	}
tavit ohanian's avatar
tavit ohanian committed
52

lanzafame's avatar
lanzafame committed
53 54
}

Lars Gierth's avatar
Lars Gierth committed
55 56
// This adds collection of net/http-related metrics
func MetricsCollectionOption(handlerName string) ServeOption {
tavit ohanian's avatar
tavit ohanian committed
57
	return func(_ *core.Dms3Node, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
lanzafame's avatar
lanzafame committed
58
		promRegistry := prometheus.NewRegistry()
59 60 61
		// Adapted from github.com/prometheus/client_golang/prometheus/http.go
		// Work around https://github.com/prometheus/client_golang/pull/311
		opts := prometheus.SummaryOpts{
tavit ohanian's avatar
tavit ohanian committed
62
			Namespace:   "dms3",
63 64 65 66 67 68 69
			Subsystem:   "http",
			ConstLabels: prometheus.Labels{"handler": handlerName},
			Objectives:  map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
		}

		reqCnt := prometheus.NewCounterVec(
			prometheus.CounterOpts{
70
				Namespace:   opts.Namespace,
71 72 73 74 75 76 77
				Subsystem:   opts.Subsystem,
				Name:        "requests_total",
				Help:        "Total number of HTTP requests made.",
				ConstLabels: opts.ConstLabels,
			},
			[]string{"method", "code"},
		)
lanzafame's avatar
lanzafame committed
78
		if err := promRegistry.Register(reqCnt); err != nil {
79 80 81 82 83 84 85
			if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
				reqCnt = are.ExistingCollector.(*prometheus.CounterVec)
			} else {
				return nil, err
			}
		}

86 87
		opts.Name = "request_duration_seconds"
		opts.Help = "The HTTP request latencies in seconds."
88
		reqDur := prometheus.NewSummaryVec(opts, nil)
lanzafame's avatar
lanzafame committed
89
		if err := promRegistry.Register(reqDur); err != nil {
90 91 92 93 94 95 96 97 98 99
			if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
				reqDur = are.ExistingCollector.(*prometheus.SummaryVec)
			} else {
				return nil, err
			}
		}

		opts.Name = "request_size_bytes"
		opts.Help = "The HTTP request sizes in bytes."
		reqSz := prometheus.NewSummaryVec(opts, nil)
lanzafame's avatar
lanzafame committed
100
		if err := promRegistry.Register(reqSz); err != nil {
101 102 103 104 105 106 107 108 109 110
			if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
				reqSz = are.ExistingCollector.(*prometheus.SummaryVec)
			} else {
				return nil, err
			}
		}

		opts.Name = "response_size_bytes"
		opts.Help = "The HTTP response sizes in bytes."
		resSz := prometheus.NewSummaryVec(opts, nil)
lanzafame's avatar
lanzafame committed
111
		if err := promRegistry.Register(resSz); err != nil {
112 113 114 115 116 117 118 119
			if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
				resSz = are.ExistingCollector.(*prometheus.SummaryVec)
			} else {
				return nil, err
			}
		}

		// Construct the mux
Lars Gierth's avatar
Lars Gierth committed
120
		childMux := http.NewServeMux()
121 122 123 124 125 126 127
		var promMux http.Handler = childMux
		promMux = promhttp.InstrumentHandlerResponseSize(resSz, promMux)
		promMux = promhttp.InstrumentHandlerRequestSize(reqSz, promMux)
		promMux = promhttp.InstrumentHandlerDuration(reqDur, promMux)
		promMux = promhttp.InstrumentHandlerCounter(reqCnt, promMux)
		mux.Handle("/", promMux)

Lars Gierth's avatar
Lars Gierth committed
128 129 130 131 132 133
		return childMux, nil
	}
}

var (
	peersTotalMetric = prometheus.NewDesc(
tavit ohanian's avatar
tavit ohanian committed
134
		prometheus.BuildFQName("dms3", "p2p", "peers_total"),
135
		"Number of connected peers", []string{"transport"}, nil)
136

137
	unixfsGetMetric = prometheus.NewSummaryVec(prometheus.SummaryOpts{
tavit ohanian's avatar
tavit ohanian committed
138
		Namespace: "dms3",
139 140 141
		Subsystem: "http",
		Name:      "unixfs_get_latency_seconds",
		Help:      "The time till the first block is received when 'getting' a file from the gateway.",
142
	}, []string{"namespace"})
Lars Gierth's avatar
Lars Gierth committed
143 144
)

tavit ohanian's avatar
tavit ohanian committed
145 146
type Dms3NodeCollector struct {
	Node *core.Dms3Node
Lars Gierth's avatar
Lars Gierth committed
147 148
}

tavit ohanian's avatar
tavit ohanian committed
149
func (_ Dms3NodeCollector) Describe(ch chan<- *prometheus.Desc) {
Lars Gierth's avatar
Lars Gierth committed
150 151 152
	ch <- peersTotalMetric
}

tavit ohanian's avatar
tavit ohanian committed
153
func (c Dms3NodeCollector) Collect(ch chan<- prometheus.Metric) {
154 155 156 157 158 159 160 161
	for tr, val := range c.PeersTotalValues() {
		ch <- prometheus.MustNewConstMetric(
			peersTotalMetric,
			prometheus.GaugeValue,
			val,
			tr,
		)
	}
Lars Gierth's avatar
Lars Gierth committed
162 163
}

tavit ohanian's avatar
tavit ohanian committed
164
func (c Dms3NodeCollector) PeersTotalValues() map[string]float64 {
165
	vals := make(map[string]float64)
166 167 168
	if c.Node.PeerHost == nil {
		return vals
	}
169 170 171 172 173 174 175 176
	for _, conn := range c.Node.PeerHost.Network().Conns() {
		tr := ""
		for _, proto := range conn.RemoteMultiaddr().Protocols() {
			tr = tr + "/" + proto.Name
		}
		vals[tr] = vals[tr] + 1
	}
	return vals
Lars Gierth's avatar
Lars Gierth committed
177
}