@cryptotaxi247 / kubo / commits / caec086c2

metrics: add prometheus back

With a proper IpfsCollector object and tests, this time. The collector object makes it easy to add further metrics, like e.g. bitswap wants/provs. License: MIT Signed-off-by: Lars Gierth <larsg@systemli.org>

Lars Gierth committed Apr 5, 2016 at 13:23 UTC caec086c2853a6f4690d18cce360e94cbd088722
5 files changed +113 -29
cmd/ipfs/daemon.go
+8 -3
@@ -27,6 +27,7 @@ import (
27 util "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
28 conn "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/net/conn"
29 peer "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/peer"
30 + prometheus "gx/ipfs/QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3/client_golang/prometheus"
31 )
32
33 const (
@@ -314,6 +315,10 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
315 return
316 }
317
318 + // initialize metrics collector
319 + prometheus.MustRegisterOrGet(&corehttp.IpfsNodeCollector{Node: node})
320 + prometheus.EnableCollectChecks(true)
321 +
322 fmt.Printf("Daemon is ready\n")
323 // collect long-running errors and block for shutdown
324 // TODO(cryptix): our fuse currently doesnt follow this pattern for graceful shutdown
@@ -376,15 +381,15 @@ func serveHTTPApi(req cmds.Request) (error, <-chan error) {
381 },
382 })
383 var opts = []corehttp.ServeOption{
379 - corehttp.PrometheusCollectorOption("api"),
384 + corehttp.MetricsCollectionOption("api"),
385 corehttp.CommandsOption(*req.InvocContext()),
386 corehttp.WebUIOption,
387 apiGw.ServeOption(),
388 corehttp.VersionOption(),
389 defaultMux("/debug/vars"),
390 defaultMux("/debug/pprof/"),
391 + corehttp.MetricsScrapingOption("/debug/metrics/prometheus"),
392 corehttp.LogOption(),
387 - corehttp.PrometheusOption("/debug/metrics/prometheus"),
393 }
394
395 if len(cfg.Gateway.RootRedirect) > 0 {
@@ -455,7 +460,7 @@ func serveHTTPGateway(req cmds.Request) (error, <-chan error) {
460 }
461
462 var opts = []corehttp.ServeOption{
458 - corehttp.PrometheusCollectorOption("gateway"),
463 + corehttp.MetricsCollectionOption("gateway"),
464 corehttp.CommandsROOption(*req.InvocContext()),
465 corehttp.VersionOption(),
466 corehttp.IPNSHostnameOption(),
core/corehttp/metrics.go new
+53
@@ -0,0 +1,53 @@
1 +package corehttp
2 +
3 +import (
4 + "net"
5 + "net/http"
6 +
7 + prometheus "gx/ipfs/QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3/client_golang/prometheus"
8 +
9 + core "github.com/ipfs/go-ipfs/core"
10 +)
11 +
12 +// This adds the scraping endpoint which Prometheus uses to fetch metrics.
13 +func MetricsScrapingOption(path string) ServeOption {
14 + return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
15 + mux.Handle(path, prometheus.UninstrumentedHandler())
16 + return mux, nil
17 + }
18 +}
19 +
20 +// This adds collection of net/http-related metrics
21 +func MetricsCollectionOption(handlerName string) ServeOption {
22 + return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
23 + childMux := http.NewServeMux()
24 + mux.HandleFunc("/", prometheus.InstrumentHandler(handlerName, childMux))
25 + return childMux, nil
26 + }
27 +}
28 +
29 +var (
30 + peersTotalMetric = prometheus.NewDesc(
31 + prometheus.BuildFQName("ipfs", "p2p", "peers_total"),
32 + "Number of connected peers", nil, nil)
33 +)
34 +
35 +type IpfsNodeCollector struct {
36 + Node *core.IpfsNode
37 +}
38 +
39 +func (_ IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) {
40 + ch <- peersTotalMetric
41 +}
42 +
43 +func (c IpfsNodeCollector) Collect(ch chan<- prometheus.Metric) {
44 + ch <- prometheus.MustNewConstMetric(
45 + peersTotalMetric,
46 + prometheus.GaugeValue,
47 + c.PeersTotalValue(),
48 + )
49 +}
50 +
51 +func (c IpfsNodeCollector) PeersTotalValue() float64 {
52 + return float64(len(c.Node.PeerHost.Network().Conns()))
53 +}
core/corehttp/metrics_test.go new
+46
@@ -0,0 +1,46 @@
1 +package corehttp
2 +
3 +import (
4 + "testing"
5 + "time"
6 +
7 + core "github.com/ipfs/go-ipfs/core"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 + bhost "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/host/basic"
10 + inet "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/net"
11 + testutil "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/test/util"
12 +)
13 +
14 +// This test is based on go-libp2p/p2p/net/swarm.TestConnectednessCorrect
15 +// It builds 4 nodes and connects them, one being the sole center.
16 +// Then it checks that the center reports the correct number of peers.
17 +func TestPeersTotal(t *testing.T) {
18 + ctx := context.Background()
19 +
20 + hosts := make([]*bhost.BasicHost, 4)
21 + for i := 0; i < 4; i++ {
22 + hosts[i] = testutil.GenHostSwarm(t, ctx)
23 + }
24 +
25 + dial := func(a, b inet.Network) {
26 + testutil.DivulgeAddresses(b, a)
27 + if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
28 + t.Fatalf("Failed to dial: %s", err)
29 + }
30 + }
31 +
32 + dial(hosts[0].Network(), hosts[1].Network())
33 + dial(hosts[0].Network(), hosts[2].Network())
34 + dial(hosts[0].Network(), hosts[3].Network())
35 +
36 + // there's something wrong with dial, i think. it's not finishing
37 + // completely. there must be some async stuff.
38 + <-time.After(100 * time.Millisecond)
39 +
40 + node := &core.IpfsNode{PeerHost: hosts[0]}
41 + collector := IpfsNodeCollector{Node: node}
42 + actual := collector.PeersTotalValue()
43 + if actual != 3 {
44 + t.Fatalf("expected 3 peers, got %d", int(actual))
45 + }
46 +}
core/corehttp/prometheus.go deleted
-25
@@ -1,25 +0,0 @@
1 -package corehttp
2 -
3 -import (
4 - "net"
5 - "net/http"
6 -
7 - prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
8 -
9 - "github.com/ipfs/go-ipfs/core"
10 -)
11 -
12 -func PrometheusOption(path string) ServeOption {
13 - return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
14 - mux.Handle(path, prom.UninstrumentedHandler())
15 - return mux, nil
16 - }
17 -}
18 -
19 -func PrometheusCollectorOption(handlerName string) ServeOption {
20 - return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
21 - childMux := http.NewServeMux()
22 - mux.HandleFunc("/", prom.InstrumentHandler(handlerName, childMux))
23 - return childMux, nil
24 - }
25 -}
package.json
+6 -1
@@ -30,6 +30,11 @@
30 "hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
31 "name": "gogo-protobuf",
32 "version": "0.0.0"
33 + },
34 + {
35 + "hash": "QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3",
36 + "name": "client_golang",
37 + "version": "0.0.0"
38 }
39 ],
40 "gxVersion": "0.4.0",
@@ -39,4 +44,4 @@
44 "license": "",
45 "name": "go-ipfs",
46 "version": "0.4.0"
42 -}
\ No newline at end of file
47 +}